20231010-遗传算法解旅行商问题-已实现-待优化

main
HYChan 3 years ago
parent 0967442654
commit 9f898444ce

@ -0,0 +1,7 @@
{
"java.project.sourcePaths": ["src"],
"java.project.outputPath": "bin",
"java.project.referencedLibraries": [
"lib/**/*.jar"
]
}

@ -0,0 +1,18 @@
## Getting Started
Welcome to the VS Code Java world. Here is a guideline to help you get started to write Java code in Visual Studio Code.
## Folder Structure
The workspace contains two folders by default, where:
- `src`: the folder to maintain sources
- `lib`: the folder to maintain dependencies
Meanwhile, the compiled output files will be generated in the `bin` folder by default.
> If you want to customize the folder structure, open `.vscode/settings.json` and update the related settings there.
## Dependency Management
The `JAVA PROJECTS` view allows you to manage your dependencies. More details can be found [here](https://github.com/microsoft/vscode-java-dependency#manage-dependencies).

@ -0,0 +1,58 @@
import java.util.Random;
public class CityPoint {
int[]DNA;//每个城市点的DNA
double[][]city;//城市点的坐标
double fitness;//城市种群的适应度
//创建种群内的城市点坐标。需要传入的参数:种群内城市数量,城市坐标(double)
//种群生成后进行杂交。交换两个城市点DNA[index]和DNA[i]交换)
public CityPoint(int city_num,double[][]city){
this.city=city;
DNA=new int[city_num];//建立一个有"city_num"个元素的DNA数组
for(int i=0;i<city_num;i++){//给DNA数组的元素逐个编号并赋跟编号一样的值
DNA[i]=i;
}
for(int i=0;i<city_num;i++){
int index=new Random().nextInt(city_num);//在种群范围内,随机生成一个数(index)
int t=DNA[index];//把指数作为DNA索引把对应指数的DNA抽出来
DNA[index]=DNA[i];//把
DNA[i]=t;
}
Fitness_cal();
}
//把本次完成迭代的城市DNA序列、适应度单独整理出来一份作为下一次迭代的初始材料。需要传入的参数DNA城市坐标(double)
public CityPoint(int[]DNA,double[][]city){
this.city=city;
this.DNA=new int[DNA.length];
for(int i=0;i<DNA.length;i++){
this.DNA[i]=DNA[i];
}
Fitness_cal();
}
//适应度计算
void Fitness_cal(){
//fit=路径长度
double fit=0;
//用两个城市点的坐标 + 向量的平行四边形法则求当前相邻两个点之间的长度即路径长度。pow(……2)意思是做平方运算sqrt()意思是开方。
//在i循环中遍历所有城市点并计算当前城市点和相邻城市点的距离直到算完所有城市点和距离
for(int i =1;i<DNA.length;i++){
fit+=Math.sqrt(Math.pow(city[DNA[i-1]][0]-city[DNA[i]][0],2))+Math.pow(city[DNA[i-1]][1]-city[DNA[i]][1],2);
}
//连完所有城市点后,记得要首尾相接,最后一个点到原点的距离也要加上
fit+=Math.sqrt(Math.pow(city[DNA[0]][0]-city[DNA[DNA.length-1]][0],2))+Math.pow(city[DNA[0]][1]-city[DNA[DNA.length-1]][1],2);
fitness=1/fit;//适应度就是路径长度的倒数
}
//打印本轮迭代生成的路径,做点可视化
void print_path(){
System.out.println("--------本次迭代路线--------");
System.out.println(DNA[0]);
for(int i=1;i<DNA.length;i++){
System.out.println("--->"+DNA[i]);
}
System.out.println("本次迭代路线适应度为:"+fitness);
System.out.println("---------------------------");
}
}

@ -0,0 +1,177 @@
import java.util.*;
public class TSP {
private static double mutate_rate=0.08;//变异概率
private static double cover_rate=0.8;//杂交概率
private static int sample_size=300;//每次迭代的种群个数
private static int city_num=30;//每个种群里的城市数量
private static int iterative=500;//迭代500代
private static double[]possible;
private static double[][]city={{ -0.07, 0.60 }, { 0.86, 0.17 }, { 0.94, -0.49 }, { 0.69, -0.54 },
{ 0.66, -0.15 }, { 0.39, 0.67 }, { 0.87, 0.08 }, { -0.97, 0.92 }, { 0.81, 0.03 }, { -0.41, 0.82 },
{ 0.10, -0.29 }, { -0.22, -0.66 }, { 0.74, -0.95 }, { -0.09, -0.24 }, { 0.93, 0.55 }, { 0.86, 0.66 },
{ -0.67, 0.80 }, { 0.14, -0.23 }, { -0.64, 0.34 }, { -0.38, -0.08 }, { -0.82, -0.75 }, { 0.40, 0.82 },
{ 0.56, 0.34 }, { -0.76, -0.08 }, { 0.78, -0.22 }, { -0.60, -0.81 }, { 0.41, -0.76 }, { 0.81, 0.52 },
{ 0.92, 0.97 }, { -0.13, -0.24 }};//城市坐标
//【*入口函数TSP整体算法主体】
public static void main(String[] args) throws Exception {
CityPoint best=null;//定义最好城市点,算法刚启动时为空
//使用CityPoint()生成城市坐标、种群列表要求生成300个种群组成样本
ArrayList<CityPoint> sample=init_group(sample_size);
//生成样本后使其迭代250代iterative=250
for(int i=0;i<iterative;i++){
//用cal_possible()方法计算种群中每个个体被选中的概率
possible=cal_possible(sample);
sample=cross(sample);
//用cal_possible()方法计算种群中每个个体被选中的概率
possible=cal_possible(sample);
sample=select(sample);
best=find_best(sample);
System.out.println();
System.out.println(String.format("【-----第%d代-----】", i+1));
System.out.println(String.format("【适应度最大值】%f", best.fitness));
System.out.println(String.format("【路程最小值】%f", 1/best.fitness));
System.out.println();
}
}
//【*主方法:初始化种群】
static ArrayList<CityPoint>init_group(int sample_group_size){ //传入样本量用CityPoint()生成新的种群,并用种群去创建样本列表
ArrayList<CityPoint> sample_group=new ArrayList<CityPoint>();
for(int i=0;i<sample_size;i++){//按样本量中要求的种群数量生成对应数量的种群300个种群为一个样本
CityPoint group_current;//生成当前种群
do{
group_current=new CityPoint(city_num, city);
}while(group_current.fitness<=0);//判断当前种群的质量,如果生成的当下种群适应度符合基本要求
sample_group.add(group_current);//就把当前种群放到样本中
}
return sample_group;//样本里够300个及格的种群后返回样本列表
}
//【*主方法:计算个体被抽中的概率】
static double[]cal_possible(ArrayList<CityPoint>group){
double[]fitness_indi=new double[group.size()];//按传入种群的元素数量创建一个列表fitness_indi[]
double fitness_total=0;
for(int i=0;i<group.size();i++){//遍历传入的种群i用于索引种群内的元素
fitness_total+=group.get(i).fitness;//适应度总和=传入种群中,当前个体的适应度相加起来
fitness_indi[i]=fitness_total;//把当前种群的总适应度记录进适应度列表fitness[]
}
for(int i=0;i<group.size();i++){
fitness_indi[i]/=fitness_total;//将每个个体的适应度值除以总适应度,从而计算每个个体被选中的概率
}
return fitness_indi;//返回储存了每个个体被选概率的数组(fitness_indi[]),这个数组将被用于抽取个体进行交叉、变异
}
//【*主方法:交叉】
static ArrayList<CityPoint> cross(ArrayList<CityPoint>father_group){//传入需要交叉的父种群
Random random=new Random();
for(int i=0;i<father_group.size()/2;i++){//对父种群的一半个体进行操作
if(random.nextDouble()<cover_rate){//每遍历一个个体,就对比一次交叉概率和随机抽取的数,如果交叉概率更大
father_group.add(get_child(father_group));//就启动用于求子代的get_child()方法,把求得子代加到传入的父种群列表里
}
}
return father_group;//最后返回交叉完毕的父种群
}
//【*辅助方法:挑选父个体】
static CityPoint sel_father(ArrayList<CityPoint>father_group){
Random random =new Random();
double t =random.nextDouble();//随机生成一个0到1之间的浮点数t用来与个体被抽中的概率进行比较
int i;//这个i之后也被当成索引用
for(i=0;i<father_group.size()-1;i++){//遍历传入种群的元素i<father_group.size()-1因为i一开始为0当i自加自加到比father_group.size()大时就会跳出循环为了避免没遍历完就提前跳出循环每次i自加完后father_group.size()都对应-1就能保证不提前跳出循环
if(possible[i]>t){//如果个体被选择的概率大于t
return father_group.get(i);//就把个体放进father_group此时这个个体就是父个体
}
}
return father_group.get(i);//返回抽中的父个体
}
//【*辅助方法:繁殖,获得子代】
static CityPoint get_child(ArrayList<CityPoint>father_group){
CityPoint parentA=sel_father(father_group);//从父种群中挑出一个父个体
CityPoint parentB=sel_father(father_group);//从父种群中挑出第二个父个体
int[]tmp=new int[city_num];//创建一个长度为个体元素数的数组30
Random random=new Random();
int indexA;//定义两个指数,作为两个父个体的交换点
int indexB;
do{
indexA=random.nextInt(city_num);//在个体中元素个数范围内,随机抽取一个指数
indexB=random.nextInt(city_num);//在个体中元素个数范围内,随机抽取第二个指数
}while(indexA==0||indexA>=indexB);//如果其中一个指数为0而另一个又是负数
int[]tmp_gene=Arrays.copyOfRange(parentA.DNA, indexA, indexB);//创建一个临时数列把父个体A中处于指数A、指数B位置的片段存入数组
int k=0,i=0;//创建临时变量i用于控制循环k是数据的索引
for(i=0;i<city_num;i++){//进行30次循环
if(k==indexA){//当遍历到第indexA个数据
for(int j=0;j<tmp_gene.length;j++){//就开始遍历存有个体A两个元素的临时数列tmp_gene
tmp[k++]=tmp_gene[j];//将tmp_gene里的元素添加到tmp数列的k+1位置中每次都放在下一个位置能防止基因重叠
}
}
if(!judge_contain(tmp_gene,parentB.DNA[i])){//判断个体B中是否包含个体A存进tmp_gene中的元素
tmp[k++]=parentB.DNA[i];//如果不包含就把个体B里的元素加到tmp数列中把个体A里没有但个体B里有的元素加进tmp数列
}
if(k>city_num){//进行到30轮即处理完一个个体内的所有元素了就跳出循环
break;
}
}
CityPoint child=mutate_child(new CityPoint(tmp, city));//传入繁殖得出的子代个体和城市坐标去用mutate_child()方法进行变异操作,得出完整的子代个体
if(child.fitness<0||child.fitness<parentA.fitness||child.fitness<parentB.fitness){//如果子代的适应度及格、适应度又比两个父个体都好
child=get_child(father_group);//就用这个优秀的子代继续繁殖……
}
return child;//顺便返回一下这个优秀的子代(每繁殖一次就输出一个子代,然后又用子代继续繁殖……)
}
//【*辅助方法:突变】
static CityPoint mutate_child(CityPoint child_group){//传入子代种群
Random random =new Random();
if(random.nextDouble()<mutate_rate){
int k1,k2;//定义两个指数,用作交换位置
do{
k1=random.nextInt(city_num);//抽取第一个指数
k2=random.nextInt(city_num);//抽取第二个指数
}while(k1==k2);//如果抽的两个指数刚好相等
int t=child_group.DNA[k1];//交换两个个体相应索引位置的片段
child_group.DNA[k1]=child_group.DNA[k2];
child_group.DNA[k2]=t;
child_group.Fitness_cal();//计算适应度
}
return child_group;//返回完成突变操作的子代种群
}
//【*辅助方法:判断某个体是否在数组中存在】
static boolean judge_contain(int list[],int indi){//传入一个数组,和一个个体
for(int i:list){//遍历数组并把当前元素放进临时变量i
if(indi==i){//比较当前元素和个体,如果当前元素和个体相等
return true;//返回真,也就是传入数组中,有这个个体
}
}
return false;//否则返回假
}
//【*主方法:选择】
static ArrayList<CityPoint>select(ArrayList<CityPoint> father_group){//传入父种群
ArrayList<CityPoint>new_group=new ArrayList<CityPoint>();
for(int i=0;i<sample_size;i++){
new_group.add(sel_father(father_group));//把符合条件的父种群逐个添加到new_group中
}
return new_group;//返回由挑选个体组成的新种群
}
//【*主方法:判断当前最优值】
static CityPoint find_best(ArrayList<CityPoint>group){
CityPoint best=group.get(0);//暂时将数组中的第一个元素视作最优解
for(CityPoint group_indi:group){//遍历传入的数组
if(group_indi.fitness>best.fitness)//每次遍历到的个体都和当前的最优解做比较,如果当前遍历的种群个体适应度>当前最优解的适应度
best=group_indi;//就把高适应度的个体换成最优解
}
return best;//返回重重比较下得出的真正最优解
}
}
Loading…
Cancel
Save