遗传算法基础练习笔记
概述:
遗传算法(Genetic Algorithm, GA)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型。
遗传算法的主要步骤如下
1、初始化种群:先随机生成一群该问题的可能解,每个解可以看成一条染色体。比如5个物品的01背包问题随机一个解为[1,0,0,1,1],构成这个解的信息是一串01数据,这就可以看成一条染色体,里面的0或1就是一个基因。一条染色体可以代表某物种的一个个体,随机生成的一堆解就可以看成一个自然生成的种群。01背包的解比较特殊,可以直接当做染色体,因为01数组的数据形式很方便后面阶段将要对染色体进行的交叉和变异操作。很多问题的解的形式比较复杂,这就需要通过编码把解的形式简化再表示染色体,等最后选出最优染色体时再解码成原问题的解的数据格式。编码的方法要具体问题具体分析,这里只需要知道有这个步骤就行。初始化步骤只需进行一次,后面的步骤都需要循环进行多次,即种群迭代多次。
2、计算适应度:生物进化的直接原因是环境改变,我们要想让一个种群按我们需要求解的方向进化,就把求解目标设为一个影响生物生存的环境因素,把生物个体(染色体)中与求解目标相关的值定为该个体的适应度。比如01背包问题的求解目标是装入背包的物品总价值最大化,种群中每个个体的染色体代表一个可能解,一个可能解对应一个装物品的方案,其中包括装入背包的物品编号、数量、重量、价值等信息。跟求解目标相关的是装入背包的物品价值,选其作为适应度就很合适。在复杂一些的问题中适应度可选的值不止一个,选不同的适应度运行效率不一样。遗传算法很多步骤是很灵活的,不同的策略往往能得到一样的结果,但是效率不一样。
3、选择下一代的父母染色体:计算完适应度就按这个标准淘汰不好的染色体(可能解),淘汰的方法有很多,最常用的是轮盘赌选择法。轮盘赌选择法要先计算每个个体的生存率=个体适应度/所有个体的适应度总和,根据每个个体的生存率画出一个扇形图,在圆心加上一根指针就是一个简易的轮盘。转动轮盘时,每个个体被指针选中的概率等于其生存率。在程序中实现轮盘赌可以把每个个体的生存率排成一列,总长为1,每个个体不重叠地占据0-1中的某个小数区间,比如1,2,3号个体生存率分别为0.1,0.2,0.3,那么对应的区间就是[0,0.1],(0.1,0.3],(0.3,0.6]。随机生成一个0-1的小数,落在哪个个体占据的区间就表示选中哪个个体。每次转动轮盘大概率会选出一个适应度较高的个体作为下一代的父母,为了保证每次迭代后总群数量不变,轮盘转动的次数要等于种群数。适应度低的个体很可能一次都没被选中从而被淘汰,适应度高的个体可能被选中很多次,这意味着优秀基因者能进行多次交配产生多个子代。轮盘赌的效率比较高,但误差较大,优化的方法也有很大,各有利弊,后面再具体介绍。轮盘赌选择是影响种群进化的决定性步骤。
4、繁衍下一代染色体:选出父母染色体后就进行下一代的繁衍,基本规则是一对父母染色体产生两个孩子染色体,然后淘汰父母染色体,这样可以保证每一代的个体数是恒定的。被选出来的父母染色体都是原种群中较为优秀的染色体,繁衍下一代是为了产生更优秀的染色体,模仿大自然的规律,把一对父母染色体随机交换一段基因,生成两个子代染色体,这两个子代可能比父母更优秀也可能更差,差的会在下一次赌轮盘中被淘汰,而好的会脱颖而出。因为优秀的基因总是能获得更多繁衍子代的机会,所以总群的基因总是向好的方向进化。因为交换染色体的结果是随机的,假如所有的父母染色体都进行基因交换,就成了随机算法,结果不可控,有可能交换后的子代染色体普遍比父母代染色体差,那样种群就退化了。因此我们可以保守一点,设一个交叉率,值取0.5-0.9,让父母染色体只有0.5-0.9的概率能交换基因片段(交配),剩下的就直接把染色体完整遗传(克隆)给下一代,这样即便交配获得的子代染色体都不好,克隆产生的子代还能保持不变,下一次赌轮盘大概率会选克隆的子代,这样种群至少也是保持不变而不会退化。
5、基因变异:生物进化的根本原因是基因突变。遗传算法生成的种群也一样,当某一个较优的染色体(可能解)在种群中占据一定数量优势时,交换染色体只会让更多染色体被它同化,最终同化完以后就不会产生更优的染色体了,所以需要基因突变,小范围改变一些基因也许会产生更优的染色体,这样就会继续进化。
一、0-1背包问题:给定 n 种物品和一背包。物品 i 的重量是wi,其价值为 vi,背包的容量为 c。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
实例:n = 10,c = 20,w =(3,1,4,5,3,6,7,8,9,7),v =(10,6,3,11,12,20,15,8,19,21)
package knapsack.problem;
/**遗传算法的资源类对象
* @author 矜君
* @date 2020/9/21 7:45.
*/
public class GeneticAlgResources01 {
//求解问题的资源:
/**
* 物品数量
*/
public int goodNum;
/**
* 背包容量(隐约束)
*/
public int capacity;
/**
* 各个物品的重量
*/
public int[] weight;
/**
* 各个物品的价值
*/
public int[] value;
//遗传算法的标配资源:
/**
* 染色体的基因数
*/
public int gene;
/**
* 种群的个体数
*/
public int populationNum;
/**
* 种群的染色体的基因序列
*/
public int[][] chromosome;
/**
* 种群适应度
*/
public int[] adaptiveness;
/**
* 种群适应度总和
*/
public int adaptivenessSum;
/**
* 总的演化代数
*/
public int generationNum;
/**
* 当前演化代数
*/
public int currGeneration = 0;
/**
* 生存者编号(有重复,足够优秀的个体可能被选中多次,这意味着它可以有多个孩子)
*/
public int[] parent;
/**
* 交叉概率
*/
public double crossoverRate;
/**
* 变异概率
*/
public double mutationRate;
/**
* 临时记录下一代的染色体
*/
public int[][] childChromosome;
/**
* 最优染色体的适应度(在本题最优适应度=最优值)
*/
public int optimalValue = 0;
/**
* 最优染色体的基因序列(最优解)
*/
public int[] optimalSolution;
/** 构造方法,只需要传入与问题相关的变量和遗传算法的四个主要影响变量
* @param goodNum 物品数量
* @param capacity 背包容量
* @param weight 物品重量
* @param value 物品价值
* @param populationNum 种群数量
* @param generationNum 遗传代数
* @param crossoverRate 交叉率
* @param mutationRate 变异率
*/
public GeneticAlgResources01(int goodNum, int capacity, int[] weight, int[] value,
int populationNum, int generationNum, double crossoverRate, double mutationRate) {
this.goodNum = goodNum;
this.capacity = capacity;
this.weight = weight;
this.value = value;
this.populationNum = populationNum;
this.generationNum = generationNum;
this.crossoverRate = crossoverRate;
this.mutationRate = mutationRate;
}
}
package knapsack.problem;
/**种群初始化
* @author 矜君
* @date 2020/9/21 8:51.
*/
public class GeneticAlgInitialization01 {
/** 初始化资源类数据,生成初代种群。
* @param ga01 资源类对象
*/
public static void initialization(GeneticAlgResources01 ga01){
//初始化资源类数据
ga01.gene=ga01.goodNum;
ga01.chromosome=new int[ga01.populationNum][ga01.gene];
ga01.adaptiveness= new int[ga01.populationNum];
ga01.parent = new int[ga01.populationNum];
ga01.childChromosome=new int[ga01.populationNum][ga01.gene];
ga01.optimalSolution = new int[ga01.gene];
//生成初代种群,直接遍历每条染色体的每个基因位置(数组元素),随机生成0和1基因。
for (int i = 0; i < ga01.populationNum; i++) {
for (int j = 0; j < ga01.gene; j++) {
double r = Math.random();
ga01.chromosome[i][j]=Math.random()>r?1:0;
}
}
}
}
package knapsack.problem;
/**计算适应度
* @author 矜君
* @date 2020/9/21 11:26.
*/
public class GeneticAlgAdaptiveness01 {
/**计算当前种群每条染色体的适应度
* @param ga01 资源对象
*/
public static void countAdaptiveness(GeneticAlgResources01 ga01){
//适应度总和是直接用+=计算的,所以要先初始化。
ga01.adaptivenessSum=0;
//零时变量,记录当前种群的最优适应度及其编号
int bestAdaptiveness = 0;
int bestAdaptivenessNo = 0;
//遍历种群个体
for (int i = 0; i < ga01.populationNum; i++) {
//记录当前染色体的物品重量和价值
int currW = 0;
int currV = 0;
//遍历基因,计算当前染色体的物品重量和价值
for (int j = 0; j < ga01.gene; j++) {
currW+=ga01.chromosome[i][j]*ga01.weight[j];
if (currW<=ga01.capacity){
currV+=ga01.chromosome[i][j]*ga01.value[j];
}else {
//如果装入物品的重量超出背包重量,则当前染色体适应度为0
currV=0;
break;
}
}
//记录染色体i的适应度
ga01.adaptiveness[i]=currV;
ga01.adaptivenessSum+=currV;
//记录当前种群的最优适应度及其编号
if (currV>bestAdaptiveness){
bestAdaptiveness = currV;
bestAdaptivenessNo = i;
}
}
//如果当前种群的最优适应度大于当前之前每一代种群的最优适应度就更新当前的最优值和最优解
if (bestAdaptiveness > ga01.optimalValue){
ga01.optimalValue = bestAdaptiveness;
ga01.optimalSolution = ga01.chromosome[bestAdaptivenessNo].clone();
}
}
}
package knapsack.problem;
/**选择父母染色体
* @author 矜君
* @date 2020/9/21 13:09.
*/
public class GeneticOperatorSelection01 {
/**从当前种群中选择较优的染色作为下一代的父母
* @param ga01 资源对象
*/
public static void rouletteWheelSelect(GeneticAlgResources01 ga01){
int n = ga01.populationNum;
//计算每个个体的生存区间(用一维数组的区间对应轮盘的扇形面积)
double[] survivalRate = new double[n];
for (int i = 0; i < n; i++) {
double temp=(double) ga01.adaptiveness[i]/ga01.adaptivenessSum;
survivalRate[i]=i==0?temp:temp+survivalRate[i-1];
}
//转动次数=种群个体数
for (int i = 0; i < n; i++) {
//用随机数代表轮盘上的指针
double temp = Math.random();
//寻找被指针选中的个体编号
for (int j = 0; j < n; j++) {
if (temp<survivalRate[j]){
//被选中个体拥有繁衍后代的权力,放入父母数组,
ga01.parent[i]=j;
break;
}
}
}
}
}
package knapsack.problem;
/**染色体交叉
* @author 矜君
* @date 2020/9/21 16:48.
*/
public class GeneticOperatorCrossover01 {
/**父母染色体交叉或复制繁衍子代
* @param ga01 资源对象
*/
public static void crossover(GeneticAlgResources01 ga01){
//遍历父母染色体
for (int i = 0; i < ga01.populationNum; i++) {
//如果随机数小于交叉率就对i和i+1这对染色体进行交叉,产生的子代复制到临时记录子代染色体的数组。
if (i+1<ga01.populationNum && Math.random()<ga01.crossoverRate){
//单点交叉,随机生成交叉点,交叉点分割的后半段基因交换
int temp = (int)(Math.random()*ga01.gene);
System.arraycopy(ga01.chromosome[ga01.parent[i]],temp+1,ga01.childChromosome[i],temp+1,ga01.gene-temp-1);
System.arraycopy(ga01.chromosome[ga01.parent[i+1]],0,ga01.childChromosome[i],0,temp);
System.arraycopy(ga01.chromosome[ga01.parent[i]],0,ga01.childChromosome[i+1],0,temp);
System.arraycopy(ga01.chromosome[ga01.parent[i+1]],temp+1,ga01.childChromosome[i+1],temp+1,ga01.gene-temp-1);
i++;
}else {
//如果随机数大于交叉率就直接复制产生子代
ga01.childChromosome[i]=ga01.chromosome[ga01.parent[i]].clone();
}
}
}
}
package knapsack.problem;
/**染色体变异
* @author 矜君
* @date 2020/9/21 18:53.
*/
public class GeneticOperatorMutation01 {
/**子代染色体变异
* @param ga01 资源类
*/
public static void mutation(GeneticAlgResources01 ga01){
//遍历子代每个染色体的每个基因
for (int i = 0; i < ga01.populationNum; i++) {
for (int j = 0; j < ga01.gene; j++) {
//如果随机数小于变异率就把当前基因进行01转换
if (Math.random()<ga01.mutationRate){
ga01.childChromosome[i][j]=1-ga01.childChromosome[i][j];
}
}
}
//变异完后子代染色体就完成了,子代染色体替换父代,准备下一次迭代
for (int i = 0; i < ga01.populationNum; i++) {
ga01.chromosome[i]=ga01.childChromosome[i].clone();
}
}
}
package knapsack.problem;
import java.util.Arrays;
/**遗传算法主线程
* @author 矜君
* @date 2020/9/21 20:09.
*/
public class GeneticAlgDemo01 {
public static void main(String[] args) {
//物品数量
int goodNum = 10;
//背包容量(隐约束)
int capacity = 20;
//各个物品的重量
int[] weight = {3,1,4,5,3,6,7,8,9,7};
//各个物品的价值
int[] value = {10,6,3,11,12,20,15,8,19,21};
//种群个体数
int populationNum = 50;
//繁衍代数
int generationNum = 50;
//交叉率
double crossoverRate = 0.6;
//变异率
double mutationRate = 0.01;
//创建遗传算法的资源对象
GeneticAlgResources01 ga01 = new GeneticAlgResources01(goodNum,capacity,weight,value,populationNum,generationNum,crossoverRate,mutationRate);
//计算开始时间
long s = System.currentTimeMillis();
//初始化种群数据
GeneticAlgInitialization01.initialization(ga01);
//计算初代种群适应度
GeneticAlgAdaptiveness01.countAdaptiveness(ga01);
//繁衍迭代
for (int i = 0; i < generationNum; i++) {
//从i代中选择第i+1代的父母染色体
GeneticOperatorSelection01.rouletteWheelSelect(ga01);
//父母染色体交叉或复制繁衍子代
GeneticOperatorCrossover01.crossover(ga01);
//子代染色体变异并替换父代染色体
GeneticOperatorMutation01.mutation(ga01);
//计算i+1代的适应度
GeneticAlgAdaptiveness01.countAdaptiveness(ga01);
}
//计算结束时间
long e = System.currentTimeMillis();
System.out.println("最优值为:" + ga01.optimalValue);
System.out.println("最优解为:" + Arrays.toString(ga01.parent));
System.out.println("计算时间为:"+(e-s)+"毫秒。");
}
}
二、旅行售货员问题:某售货员要到若干城市去推销商品,一直各城市之间的路程,他要选定一条从驻地出发,经过每个城市一遍,最后回到住地的路线,使总的路程最短。
package travelling.salesman.problem;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @author 矜君
* @date 2020/9/24 23:39.
*/
public class GA01 {
/**
* 城市数量
*/
private int n;
/**
* 出发城市
*/
private int startCity;
/**
* 城市的邻接矩阵
*/
private double[][] map;
/**
* 基因数
*/
private int gene;
/**
* 初代种群数量
*/
private int populationNum;
/**
* 初代种群的染色体的基因序列
*/
private int[][] chromosome;
/**
* 初代种群适应度
*/
private double[] adaptiveness;
/**
* 种群适应度总和
*/
private double adaptivenessSum;
/**
* 总的演化代数
*/
private int generationNum;
/**
* 当前演化代数
*/
private int currGeneration = 0;
/**
* 生存率
*/
private double[] survivalRate;
/**
* 生存者编号(有重复,足够优秀的个体可能被选中多次,这意味着它可以有多个孩子)
*/
private int[] parent;
/**
* 交叉概率
*/
private double matingRate;
/**
* 变异概率
*/
private double variationRate;
/**
* 初代种群的染色体的基因序列
*/
private int[][] childChromosome;
/**
* 最优染色体的适应度
*/
private double optimalValue = Double.MAX_VALUE;
/**
* 最优染色体的基因序列
*/
private int[] optimalSolution;
public GA01(int n, int startCity, double[][] map, int populationNum, int generationNum, double matingRate, double variationRate) {
this.n = n;
this.startCity = startCity;
this.map = map;
this.populationNum = populationNum;
this.generationNum = generationNum;
this.matingRate = matingRate;
this.variationRate = variationRate;
}
/**
* 生成初始种群
*/
private void initialization(){
if (currGeneration==0){
gene=n;
chromosome=new int[populationNum][gene];
adaptiveness= new double[populationNum];
survivalRate = new double[populationNum];
parent = new int[populationNum];
childChromosome=new int[populationNum][gene];
for (int i = 0; i < populationNum; i++) {
/*确保每个城市只出现一遍*/
boolean[] b = new boolean[gene];
chromosome[i][0] = startCity;
b[0] = true;
int j = gene;
while (j>0){
if (j==startCity){
j--;
continue;
}
int r = (int)(Math.random()*(gene-1))+1;
if (!b[r]){
chromosome[i][r]=j;
j--;
b[r]=true;
}
}
}
countAdaptiveness();
/*rouletteWheelSelect();
mating();*/
}
}
/**
* 计算适应度
*/
private void countAdaptiveness(){
/* System.out.print("种群:");
for (int[] ints : chromosome) {
System.out.print(Arrays.toString(ints)+" ");
}
System.out.println(" ");*/
adaptivenessSum=0;
double bestAdaptiveness = Double.MAX_VALUE;
int bestAdaptivenessNo = 0;
for (int i = 0; i < populationNum; i++) {
int previousCity = startCity;
double currCost = 0;
for (int j = 1; j < gene; j++) {
int currCity = chromosome[i][j];
if (map[previousCity][currCity]!=0){
currCost+=map[previousCity][currCity];
}else {
currCost=Double.MAX_VALUE;
break;
}
if (j==gene-1 ){
if (map[currCity][startCity]!=0){
currCost+=map[currCity][startCity];
}else {
currCost=Double.MAX_VALUE;
break;
}
}
previousCity = currCity;
}
/* if (currCost==22){
System.out.println("出问题的代数:"+currGeneration);
}*/
if (currCost<bestAdaptiveness){
bestAdaptiveness = currCost;
bestAdaptivenessNo = i;
}
if (currCost<Double.MAX_VALUE){
adaptiveness[i] = (1.0/currCost);
adaptivenessSum += adaptiveness[i];
}
}
//averageAdaptiveness = (bestAdaptiveness+worstAdaptiveness)/2;
if (bestAdaptiveness < optimalValue){
optimalValue = bestAdaptiveness;
optimalSolution = chromosome[bestAdaptivenessNo].clone();
}
/*System.out.print("适应力:");
for (int i = 0; i < populationNum; i++) {
System.out.print(1.0/adaptiveness[i]+" ");
}*/
}
/**
* 轮盘赌选择
*/
private void rouletteWheelSelect(){
//计算适应度区间,路程越远,适应度越差,但是路程必须记录,所以在求生存率时再取倒数
for (int i = 0; i < populationNum; i++) {
double temp= adaptiveness[i]/adaptivenessSum;
survivalRate[i]=i==0?temp:temp+survivalRate[i-1];
}
/* System.out.print("生存率:");
System.out.println(Arrays.toString(survivalRate));
System.out.print("指针:[");*/
/* int number = 0;
while (number<populationNum){
double temp = Math.random();
for (int j = 0; j < populationNum; j++) {
if (temp<survivalRate[j] && adaptiveness[j]>=averageAdaptiveness){
parent[number]=j;
number++;
break;
}
}
}*/
for (int i = 0; i < populationNum; i++) {
double temp = Math.random();
// System.out.print(temp+",");
for (int j = 0; j < populationNum; j++) {
if (temp<survivalRate[j]){
// System.out.print(j+"😂");
parent[i]=j;
break;
}
}
}
//测试
/* System.out.println("种群:");
double allAdap1 = 0;
for (int i = 0; i < populationNum; i++) {
double a1 = 1.0/adaptiveness[i];
allAdap1+=a1;
System.out.print((i+1)+"号,适应度:"+a1+"|");
if ((i+1)%5==0){
System.out.println(" ");
}
}
System.out.println("总适应度:"+allAdap1);
System.out.println("父母:");
double allAdap2 = 0;
for (int i = 0; i < populationNum; i++) {
double a2 = 1.0/adaptiveness[parent[i]];
allAdap2 += a2;
System.out.print((parent[i]+1)+"号,适应度:"+a2+"|");
if ((i+1)%5==0){
System.out.println(" ");
}
}
System.out.println("总适应度:"+allAdap2);
System.out.println("最优值:"+optimalValue);
*/
/*
System.out.println("]");
System.out.print("父母:");
System.out.println(Arrays.toString(parent));*/
}
/**
* 生存者交换或复制染色体产生子代。
*/
private void mating(){
for (int i = 0; i < populationNum; i++) {
if (i+1<populationNum && Math.random()<matingRate){
//双点交叉
int temp1 = (int)(Math.random()*(gene-1))+1;
int temp2 = (int)(Math.random()*(gene-1))+1;
if (temp2 - temp1>0){
temp2 -= temp1;
}else if (temp2-temp1<0){
int t1 = temp1;
temp1 = temp2;
temp2 = -temp2+t1;
}else {
temp2=1;
}
//先复制交叉部分到子代
System.arraycopy(chromosome[parent[i]],temp1,childChromosome[i+1],temp1,temp2);
System.arraycopy(chromosome[parent[i+1]],temp1,childChromosome[i],temp1,temp2);
int[] c1 = Arrays.copyOfRange(childChromosome[i+1],temp1,temp1+temp2);
int[] c2 = Arrays.copyOfRange(childChromosome[i],temp1,temp1+temp2);
for (int j = 0; j < temp2; j++) {
for (int k = 0; k < temp2; k++) {
if (c1[j]==c2[k]){
c1[j]=0;
c2[k]=0;
}
}
}
for (int j = 0; j < gene; j++) {
if (j>=temp1&&j<temp1+temp2){
continue;
}
boolean b1 = false;
boolean b2 = false;
for (int k = temp1; k < temp1+temp2; k++) {
if (chromosome[parent[i]][j] == childChromosome[i][k]){
for (int l = 0; l < temp2; l++) {
if (c1[l]!=0){
childChromosome[i][j] = c1[l];
c1[l]=0;
break;
}
}
b1 = true;
}
if (chromosome[parent[i+1]][j] == childChromosome[i+1][k]){
for (int l = 0; l < temp2; l++) {
if (c2[l]!=0){
childChromosome[i+1][j] = c2[l];
c2[l]=0;
break;
}
}
b2 = true;
}
if (b1&&b2){
break;
}
}
if (!b1){
childChromosome[i][j]=chromosome[parent[i]][j];
}
if (!b2){
childChromosome[i+1][j]=chromosome[parent[i+1]][j];
}
}
int aa = 0;
for (int i1 : childChromosome[i]) {
if (i1==3){
aa++;
}
}
if (aa<2){
aa = 0;
for (int i1 : childChromosome[i + 1]) {
if (i1==3) aa++;
}
}
if (aa>=2){
System.out.println("交叉点:"+temp1+" "+temp2);
System.out.println(Arrays.toString(chromosome[parent[i]]));
System.out.println(Arrays.toString(chromosome[parent[i+1]]));
System.out.println(Arrays.toString(childChromosome[i]));
System.out.println(Arrays.toString(childChromosome[i+1]));
System.out.println("----------------------");
//variation(i);
}
variation(i);
variation(i+1);
i++;
}else {
childChromosome[i]=chromosome[parent[i]].clone();
}
}
}
/**
* 基因变异
*/
private void variation(int i){
if (Math.random()<variationRate){
int temp1 = (int)(Math.random()*(gene-1))+1;
int temp2 = (int)(Math.random()*(gene-1))+1;
if (temp2 - temp1>0){
temp2 -= temp1;
}else if (temp2-temp1<0){
int t1 = temp1;
temp1 = temp2;
temp2 = -temp2+t1;
}else {
temp2=1;
}
int[] temp3 = new int[temp2];
System.arraycopy(childChromosome[i],temp1,temp3,0,temp2);
for (int j = temp2-1; j >=0 ; j--) {
childChromosome[i][temp1] = temp3[j];
temp1++;
}
/*int j = temp1;
for (int k = temp1+temp2-1; k >= temp1; k--) {
childChromosome[i][j]=temp3[k];
}*/
}
}
private void update(){
for (int i = 0; i < populationNum; i++) {
chromosome[i]=childChromosome[i].clone();
}
countAdaptiveness();
currGeneration++;
}
private void optimal(){
if (currGeneration>generationNum) {
// System.out.println(Arrays.toString(adaptiveness));
System.out.println("最优值为:" + optimalValue);
System.out.println("最优解为:" + Arrays.toString(optimalSolution));
}
}
public void geneticAlg(){
while (currGeneration <= generationNum){
initialization();
rouletteWheelSelect();
mating();
update();
optimal();
}
}
public static void main(String[] args) {
int n = 4;
int starCity = 1;
double[][] map = new double[n+1][n+1];
//地图数据初始化
map[1][2] = 30;map[1][3] = 6; map[1][4] = 4;
map[2][1] = 30;map[2][3] = 5; map[2][4] = 10;
map[3][1] = 6; map[3][2] = 5; map[3][4] = 20;
map[4][1] = 4; map[4][2] = 10;map[4][3] = 20;
for (int i = 0; i < 10; i++) {
GA01 ga01 = new GA01(n,starCity,map,50,50,0.6,0.01);
long s = System.currentTimeMillis();
ga01.geneticAlg();
long e = System.currentTimeMillis();
System.out.println("计算时间:"+(e-s)+"毫秒");
System.out.println("---------------------");
}
}
}
三、最小生成树:设G = (V, E)是无向连通带权图,即一个网络。E中每条边(v, w)的权为c[v][w]
。如果 G 的子图 G' 是一棵包含 G 的所有顶点的树,则称 G' 为 G 的生成树。生成树上各边权的总和称为该生成树的耗费。在 G 的所有生成树中,耗费最小的生成树称为 G 的最小生成树。
package minimum.spanning.tree;
import java.util.Arrays;
/**
* @author 矜君
* @date 2020/9/26 12:23.
*/
public class GA01 {
/**
*顶点数
*/
private int vertex;
/**
*边集
*/
private double[][] edge;
public GA01(int vertex, double[][] edge, int populationNum, int generationNum, double matingRate, double variationRate) {
this.vertex = vertex;
this.edge = edge;
this.populationNum = populationNum;
this.generationNum = generationNum;
this.matingRate = matingRate;
this.variationRate = variationRate;
}
/**
* 基因数
*/
private int gene;
/**
* 初代种群数量
*/
private int populationNum;
/**
* 初代种群的染色体的基因序列
*/
private int[][] chromosome;
/**
* 初代种群适应度
*/
private double[] adaptiveness;
/**
* 种群适应度总和
*/
private double adaptivenessSum;
/**
* 总的演化代数
*/
private int generationNum;
/**
* 当前演化代数
*/
private int currGeneration = 0;
/**
* 生存率
*/
private double[] survivalRate;
/**
* 生存者编号(有重复,足够优秀的个体可能被选中多次,这意味着它可以有多个孩子)
*/
private int[] parent;
/**
* 交叉概率
*/
private double matingRate;
/**
* 变异概率
*/
private double variationRate;
/**
* 初代种群的染色体的基因序列
*/
private int[][] childChromosome;
/**
* 最优染色体的适应度
*/
private int optimalValue = Integer.MAX_VALUE;
/**
* 最优染色体的基因序列
*/
private int[] optimalSolution;
/**
* 记录每个染色体中最大点所连的另一点
*/
private int[] maxToV;
/**
* 记录子代每个染色体中最大点所连的另一点
*/
private int[] childMaxToV;
/**
* 生成初始种群
*/
private void initialization() {
if (currGeneration == 0) {
gene = vertex-1;
chromosome = new int[populationNum][gene];
adaptiveness = new double[populationNum];
survivalRate = new double[populationNum];
parent = new int[populationNum];
maxToV = new int[populationNum];
childMaxToV = new int[populationNum];
childChromosome = new int[populationNum][gene];
optimalSolution = new int[gene];
for (int i = 0; i < populationNum; i++) {
ArrayList<Integer> a = new ArrayList<>();
ArrayList<Integer> b = new ArrayList<>();
for (int j = 1; j < vertex; j++) {
b.add(j);
}
while (true){
int k = (int)(Math.random()*(vertex-1)+1);
if (edge[vertex][k] != 0){
chromosome[i][k-1] = vertex;
maxToV[i] = k-1;
a.add(k);
b.remove(Integer.valueOf(k));
break;
}
}
int eNum = 0;
while (eNum<gene-1){
for (Integer i1 : a) {
boolean bk = false;
for (Integer i2 : b) {
double r = Math.random();
if (Math.random() < r && edge[i1][i2] != 0) {
/*int aa = chromosome[i][j];
if (aa!=vertex&&chromosome[i][aa-1]==j+1){*/
if (chromosome[i][i2-1] == 0 && chromosome[i][i1-1]!= i2) {
chromosome[i][i2-1] = i1;
a.add(i2);
b.remove(i2);
eNum++;
bk = true;
break;
}
}
}
if (bk) {
break;
}
}
}
}
/* for (int i = 0; i < populationNum; i++) {
for (int j = 0; j < gene; j++) {
int a = chromosome[i][j];
if (a!=vertex && chromosome[i][a-1]==j+1){
chromosome[i][j] = chromosome[i+1][j];
}
}
}*/
countAdaptiveness();
//测试
/*rouletteWheelSelect();
mating();*/
}
}
/**
* 计算适应度
*/
private void countAdaptiveness(){
/* System.out.print("种群:");
for (int[] ints : chromosome) {
System.out.print(Arrays.toString(ints)+" ");
}
System.out.println(" ");*/
//初始化
adaptivenessSum=0;
//记录当前种群中最优适应度个体
int bestAdaptiveness = Integer.MAX_VALUE;
int bestAdaptivenessNo = 0;
for (int i = 0; i < populationNum; i++) {
int dist = 0;
// boolean bk = false;
for (int j = 0; j < gene; j++) {
/* int aa = chromosome[i][j];
if (aa!=vertex&&chromosome[i][aa-1]==j+1){
*//*x++;
System.out.println("重复染色体:"+currGeneration+"代"+i+"号");
System.out.println(Arrays.toString(chromosome[i]));*//*
adaptiveness[i]=0;
bk = true;
break;
}*/
dist+=edge[j+1][chromosome[i][j]];
}
if (dist<bestAdaptiveness){
bestAdaptiveness = dist;
bestAdaptivenessNo = i;
}
// if (!bk){
adaptiveness[i] = 1.0/(double)dist;
adaptivenessSum += adaptiveness[i];
// }
}
//如果当前种群中适应度最高的个体比最优值个体好好,就更新
if (bestAdaptiveness < optimalValue){
optimalValue = bestAdaptiveness;
optimalSolution = chromosome[bestAdaptivenessNo].clone();
}
/* for (int i = 0; i < populationNum; i++) {
System.out.println(Arrays.toString(chromosome[i])+"适应度:"+adaptiveness[i]);
}*/
/* System.out.print("适应力:");
System.out.println(Arrays.toString(adaptiveness));*/
}
/**
* 轮盘赌选择
*/
private void rouletteWheelSelect(){
//计算适应度区间
for (int i = 0; i < populationNum; i++) {
double temp= adaptiveness[i]/adaptivenessSum;
survivalRate[i]=i==0?temp:temp+survivalRate[i-1];
}
/* System.out.print("生存率:");
System.out.println(Arrays.toString(survivalRate));
System.out.print("指针:[");*/
for (int i = 0; i < populationNum; i++) {
double temp = Math.random();
// System.out.print(temp+",");
for (int j = 0; j < populationNum; j++) {
if (temp<survivalRate[j]){
// System.out.print(j+"😂");
parent[i]=j;
break;
}
}
}
/*System.out.println("]");*/
/*测试
System.out.println("种群:");
double allAdap1 = 0;
for (int i = 0; i < populationNum; i++) {
double a1 = 1.0/adaptiveness[i];
allAdap1+=a1;
System.out.print((i+1)+"号,适应度:"+a1+"|");
if ((i+1)%5==0){
System.out.println(" ");
}
}
System.out.println("总适应度:"+allAdap1);
System.out.println("父母:");
double allAdap2 = 0;
for (int i = 0; i < populationNum; i++) {
double a2 = 1.0/adaptiveness[parent[i]];
allAdap2 += a2;
System.out.print((parent[i]+1)+"号,适应度:"+a2+"|");
if ((i+1)%5==0){
System.out.println(" ");
}
}
System.out.println("总适应度:"+allAdap2);
System.out.println("最优值:"+optimalValue);
*/
}
/**
* 生存者交换或复制染色体产生子代。
*/
private void mating(){
for (int i = 0; i < populationNum; i++) {
//i和i+1凑一对交换,
if (i+1<populationNum && Math.random()<matingRate){
//双点交叉
int temp1 = (int)(Math.random()*(gene-1))+1;
int temp2 = (int)(Math.random()*(gene-1))+1;
if (temp2 - temp1>0){
temp2 -= temp1;
}else if (temp2-temp1<0){
int t1 = temp1;
temp1 = temp2;
temp2 = -temp2+t1;
}else {
temp2=1;
}
//先复制交叉部分到子代
//System.arraycopy(chromosome[parent[i]],temp1,childChromosome[i+1],temp1,temp2);
//System.arraycopy(chromosome[parent[i+1]],temp1,childChromosome[i],temp1,temp2);
for (int j = temp1; j < temp1+temp2; j++) {
int a = chromosome[parent[i]][j];
int b = chromosome[parent[i+1]][j];
if (a!=vertex && chromosome[parent[i+1]][a-1]==j+1){
childChromosome[i+1][j] = chromosome[parent[i+1]][j];
}else {
childChromosome[i+1][j] = chromosome[parent[i]][j];
}
if (b!=vertex && chromosome[parent[i]][b-1]==j+1){
childChromosome[i][j] = chromosome[parent[i]][j];
}else {
childChromosome[i][j] = chromosome[parent[i+1]][j];
}
}
//复制交叉前段
if (temp1>0){
System.arraycopy(chromosome[parent[i]],0,childChromosome[i],0,temp1);
System.arraycopy(chromosome[parent[i+1]],0,childChromosome[i+1],0,temp1);
}
if (temp1+temp2<gene){
System.arraycopy(chromosome[parent[i]],temp1+temp2,childChromosome[i],temp1+temp2,gene-(temp1+temp2));
System.arraycopy(chromosome[parent[i+1]],temp1+temp2,childChromosome[i+1],temp1+temp2,gene-(temp1+temp2));
}
boolean b1 = maxToV[parent[i]]>=temp1 && maxToV[parent[i]]<(temp1+temp2) && (maxToV[parent[i+1]]<temp1 || maxToV[parent[i+1]]>=(temp1+temp2));
boolean b2 = (maxToV[parent[i]]<temp1 || maxToV[parent[i]]>=(temp1+temp2)) && maxToV[parent[i+1]]>=temp1 && maxToV[parent[i+1]]<(temp1+temp2);
boolean b3 = maxToV[parent[i]]>=temp1 && maxToV[parent[i]]<(temp1+temp2) && maxToV[parent[i+1]]>=temp1 && maxToV[parent[i+1]]<(temp1+temp2);
if (b1){
int a = childChromosome[i][maxToV[parent[i+1]]];
if (Math.random()<(double) 1/vertex && a!=vertex && childChromosome[i+1][a-1]!=maxToV[parent[i+1]]+1){
childChromosome[i+1][maxToV[parent[i+1]]] = childChromosome[i][maxToV[parent[i+1]]];
childMaxToV[i+1]=maxToV[parent[i]];
}else {
childMaxToV[i+1]=maxToV[parent[i+1]];
}
childChromosome[i][maxToV[parent[i+1]]] = vertex;
childMaxToV[i]=maxToV[parent[i+1]];
}else if (b2){
int a = childChromosome[i+1][maxToV[parent[i]]];
if (Math.random()<(double) 1/vertex && a!=vertex && childChromosome[i][a-1]!=maxToV[parent[i]]+1){
childChromosome[i][maxToV[parent[i]]] = childChromosome[i+1][maxToV[parent[i]]];
childMaxToV[i]=maxToV[parent[i+1]];
}else {
childMaxToV[i]=maxToV[parent[i]];
}
childChromosome[i+1][maxToV[parent[i]]] = vertex;
childMaxToV[i+1]=maxToV[parent[i]];
}else if (b3){
childMaxToV[i]=maxToV[parent[i+1]];
childMaxToV[i+1]=maxToV[parent[i]];
}else {
childMaxToV[i]=maxToV[parent[i]];
childMaxToV[i+1]=maxToV[parent[i+1]];
}
boolean print = false;
for (int j = 0; j < gene; j++) {
int a = childChromosome[i][j];
int b = childChromosome[i+1][j];
if (a!=vertex&&childChromosome[i][a-1]==j+1){
print =true;
}else if (b!=vertex&&childChromosome[i+1][b-1]==j+1){
print = true;
}
}
if (print){
System.out.println("交叉点:"+temp1+" "+temp2+" 最大点坐标:"+maxToV[parent[i]]+" "+maxToV[parent[i+1]]);
System.out.println(Arrays.toString(chromosome[parent[i]]));
System.out.println(Arrays.toString(chromosome[parent[i+1]]));
if (b1||b2){
System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
}
System.out.println(Arrays.toString(childChromosome[i]));
System.out.println(Arrays.toString(childChromosome[i+1]));
System.out.println("----------------------");
variation(i);
}
variation(i);
i++;
}else {
childChromosome[i]=chromosome[parent[i]].clone();
childMaxToV[i]=maxToV[parent[i]];
}
}
}
/**
* 基因变异
*/
private void variation(int i){
for (int j = 0; j < gene; j++) {
if (Math.random()<variationRate && childChromosome[i][j] != vertex){
int temp;
do {
temp = (int) (Math.random()*populationNum);
} while (temp == i);
int k = chromosome[temp][j];
if (k!=vertex && childChromosome[i][k-1] != j+1){
childChromosome[i][j] = k;
}
if (k==vertex){
childChromosome[i][j] = k;
}
}
if (Math.random()<variationRate && childChromosome[i+1][j] != vertex){
int temp;
do {
temp = (int) (Math.random()*populationNum);
} while (temp == i+1);
int k = chromosome[temp][j];
if (k!=vertex && childChromosome[i+1][k-1] != j+1){
childChromosome[i+1][j] = k;
}
if (k==vertex){
childChromosome[i+1][j] = k;
}
}
}
/* System.out.println("变异后:");
System.out.println(Arrays.toString(childChromosome[i]));
System.out.println(Arrays.toString(childChromosome[i+1]));*/
}
private void update(){
for (int i = 0; i < populationNum; i++) {
chromosome[i]=childChromosome[i].clone();
}
maxToV = childMaxToV.clone();
countAdaptiveness();
currGeneration++;
}
private void optimal(){
if (currGeneration>generationNum) {
/* System.out.println("适应度:");
for (double v : adaptiveness) {
System.out.print((1.0/v)+" ");
}
System.out.println(" ");*/
System.out.println("最优值为:" + optimalValue);
System.out.println("最优解为:" + Arrays.toString(optimalSolution));
// System.out.println("有重复边的个体数:"+x);
}
}
public void geneticAlg(){
while (currGeneration<= generationNum){
initialization();
rouletteWheelSelect();
mating();
update();
optimal();
}
}
public static void main(String[] args) {
//点数
int vertex = 6;
//无向图G的顶点集合v
//int[] vertex = new int[n+1];
//无向图G的边集合E
double[][] edge = new double[vertex+1][vertex+1];
//最小生成树MST的边集合,点集不用变。
//int[][] mstEege = new int[n+1][n+1];
//inputGraph(vertex,edge,mstEege);//输入图数据
edge[1][2]=10; edge[2][1]=10; edge[1][3]=21; edge[3][1]=21;
edge[1][5]=8; edge[5][1]=8; edge[2][3]=18; edge[3][2]=18;
edge[2][4]=5; edge[4][2]=5; edge[2][6]=6; edge[6][2]=6;
edge[3][5]=25; edge[5][3]=25; edge[3][6]=19; edge[6][3]=19;
edge[4][6]=7; edge[6][4]=7; edge[5][6]=33; edge[6][5]=33;
for (int i = 0; i < 10; i++) {
GA01 ga01 = new GA01(vertex,edge,50,50,0.5,0.01);
long s = System.currentTimeMillis();
ga01.geneticAlg();
long e = System.currentTimeMillis();
System.out.println("计算时间:"+(e-s)+"毫秒");
System.out.println("--------------------------");
}
}
}
四、行业协会:
参数:
N:企业集合
i,j:企业的角标, i,j∈N
{pij}:收益矩阵,pij表示企业i从企业j获得收益(由于信息共享)
ci:企业i 的信息共享成本(如果加入平台)
r:企业加入平台的最低收益率门槛值
Y:补贴金额的总预算值
T:要求的业内企业加入平台的最低比率
M:一个大数
变量:
xi:0/1变量,表示企业i是否愿意加入平台,1--是,0--否。
bi:0/1变量,表示对企业i是否收费,1--是(收费),0--否(补贴)。
yi:非负连续变量,表示对企业i的补贴金额。
zi:非负连续变量,表示对企业i的收费金额。
qi:连续变量,表示企业i的净收益。
package trade.association;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Scanner;
/**
* @author 矜君
* @date 2020/9/6 21:51.
*/
public class TradeAssociation {
public static void main(String[] args) throws IOException {
//企业个数
int n;
//企业的信息共享成本(如果加入平台)
double[] c;
//收益矩阵
double[][] profit;
//企业加入平台的最低收益率门槛值
double r = 0.1;
//补贴金额的总预算值(补贴上限值)
double yY = 1000;
//要求的业内企业加入平台的最低比率
double tT = 0.6;
//一个大数
double mM = 9999;
/*Scanner sc = new Scanner(System.in);
System.out.println("请输入计算参数的文件路径名:");
String fileName = sc.nextLine();*/
FileReader fileReader = new FileReader("C:\\Users\\矜君\\Desktop\\新建文件夹 (2)\\data_300.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line =bufferedReader.readLine();
n=(int) getDoubleValue(line);
c = new double[n];
profit = new double[n][n];
int a = 0;
while (line!=null){
line = bufferedReader.readLine();
if (a<n){
c[a]=getDoubleValue(line);
a++;
}else if (a<2*n){
profit[a-n]= Arrays.copyOf(getDoubleArrays(line,n),n);
a++;
}
}
bufferedReader.close();
fileReader.close();
Date date1 = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("HH-mm-ss");
String str1 = formatter.format(date1);
/* System.out.println("请输入存放计算结果的文件夹路径名:");
String str2 = sc.nextLine();
sc.close();
str2=str2+"\\计算结果-"+str1+".txt";*/
/*String str2 = "C:\\Users\\矜君\\Desktop\\新建文件夹 (2)\\计算结果-"+str1+".txt";
File file1 = new File(str2);
FileWriter fw1 = new FileWriter(file1);
BufferedWriter bw1 = new BufferedWriter(fw1);
bw1.write("------------------------------------------------------------------------------------------------------------\t\n");
*/
//记录开始计算的时间
long s1 = System.currentTimeMillis();
//调用求最大化协会收益的函数
maxRevenue(n,c,profit,r,yY,tT,mM);
//记录结束计算的时间
long e1 = System.currentTimeMillis();
System.out.println("计算时间:"+(e1-s1)+" 微秒");
/* bw1.write(" 计算时间:"+(e1-s1)+"微秒\t\n");
bw1.write("------------------------------------------------------------------------------------------------------------\t\n");
//记录开始计算的时间
long s2 = System.currentTimeMillis();
//调用求最大化参与企业数的函数
// maxParticipation(n,c,profit,r,yY,tT,mM,bw1);
//记录结束计算的时间
long e2 = System.currentTimeMillis();
bw1.write(" 计算时间:"+(e2-s2)+"微秒\t\n");
bw1.write("------------------------------------------------------------------------------------------------------------\t\n");
bw1.flush();
bw1.close();
System.out.println("计算结果的路径名:"+str2);*/
}
public static void maxRevenue(int n,double[]c,double[][] profit,double r,double yY,double tT,double mM/*,BufferedWriter bw1*/) throws IOException {
//遗传算法:
// 基因数=n
// 初代种群数量
int populationNum = 50;
// 初代种群的染色体的基因序列
int[][] chromosome = new int[populationNum][n];
// 初代种群适应度
double[][] adaptiveness = new double[populationNum][2];
// 种群适应度总和
double adaptivenessSum = 0;
//总的演化代数
int generationNum = 100;
//当前演化代数
int currGeneration = 0;
// 生存率
double[] survivalRate = new double[populationNum];
// 生存者编号(有重复,足够优秀的个体可能被选中
// 多次,这意味着它可以有多个孩子)
int[] parent = new int[populationNum];
// 交叉概率
double matingRate = 0.6;
//变异概率
double variationRate = 0.01;
//优秀比例
double excellenceRate = 0.2;
//精英数量
int eliteNum = (int)(populationNum *excellenceRate);
// 初代种群的染色体的基因序列
int[][] childChromosome = new int[populationNum][n];
// 最优染色体的适应度
int optimalNo = 0;
//协会总补贴
double[] subsidy = new double[populationNum];
//加入企业数量
int[] join = new int[populationNum];
//连续变量,表示企业i的净收益。
double[][] q = new double[populationNum][n];
//非负连续变量,表示对企业i的收费金额。
double[][] z = new double[populationNum][n];
//非负连续变量,表示对企业i的补贴金额。
double[][] y = new double[populationNum][n];
// 生成初始种群
for (int i = 0; i < populationNum; i++) {
for (int j = 0; j < n; j++) {
chromosome[i][j]=Math.random()>0.5?1:0;
}
}
//计算初代适应性
for (int i = 0; i < populationNum; i++) {
adaptiveness[i][0]=i;
//adaptiveness[i][1]=0;
for (int j = 0; j < n; j++) {
if (chromosome[i][j]==1){
double sum = 0;
double threshold1;
for (int k = 0; k < n; k++) {
sum+=chromosome[i][k]*profit[j][k];
}
q[i][j]=sum-c[j];
threshold1 = q[i][j]-r*c[j];
if (threshold1>0){
z[i][j]=threshold1/(1+r);
if (z[i][j]<=mM){
q[i][j]-=z[i][j];
adaptiveness[i][1]+=threshold1/(1+r);
}//else{报错}
}else if (-threshold1<=mM){
y[i][j]=-threshold1;
subsidy[i]+=y[i][j];
q[i][j]+=y[i][j];
}
join[i]++;
}
}
/* if ((double)join[i]/n>=tT){
System.out.println(Arrays.toString(chromosome[i]));
System.out.println(join[i]);
System.out.println((double)join[i]/n);
System.out.println("收费:"+adaptiveness[i][1]);
System.out.println("补贴:"+subsidy[i]);
}*/
if (subsidy[i]<=yY && (double)join[i]/n>=tT){
adaptiveness[i][1]-=subsidy[i];
//System.out.println("收益1:"+adaptiveness[i][1]);
}else {
/*if ((double)join[i]/n>=tT){
System.out.println("收益2:"+adaptiveness[i][1]);
}*/
adaptiveness[i][1]=-mM;
subsidy[i]=0;
}
adaptivenessSum+=adaptiveness[i][1];
}
Arrays.sort(adaptiveness,((o1, o2) -> (int) (o2[1]-o1[1])));
/* System.out.println("最优解:");
System.out.println(Arrays.toString(chromosome[(int) adaptiveness[0][0]]));
System.out.println(join[(int) adaptiveness[0][0]]);
System.out.println((double)join[(int) adaptiveness[0][0]]/n);
System.out.println("收费:"+(adaptiveness[0][1]+subsidy[(int) adaptiveness[0][0]]));
System.out.println("补贴:"+subsidy[(int) adaptiveness[0][0]]);
System.out.println("收益:"+adaptiveness[0][1]);*/
while (currGeneration<generationNum){
//轮盘赌选择
for (int i = 0; i < populationNum; i++) {
double temp= adaptiveness[i][1]/adaptivenessSum;
survivalRate[i]=i==0?temp:temp+survivalRate[i-1];
}
for (int i = 0; i < populationNum; i++) {
double temp = Math.random();
for (int j = 0; j < populationNum; j++) {
if (temp<survivalRate[j]){
parent[i]=j;
break;
}
}
}
//生存者交换或复制染色体产生子代。
//精英染色体直接复制
for (int i = 0; i < eliteNum; i++) {
childChromosome[i]=chromosome[(int) adaptiveness[i][0]].clone();
}
//选出的染色体交叉产生下一代
for (int i = eliteNum; i < populationNum; i+=2) {
if (i+1<populationNum){
if (Math.random()<matingRate){
int temp = (int)(Math.random()* n);
System.arraycopy(chromosome[parent[i]],temp+1,childChromosome[i],temp+1, n -temp-1);
System.arraycopy(chromosome[parent[i+1]],0,childChromosome[i],0,temp);
System.arraycopy(chromosome[parent[i]],0,childChromosome[i+1],0,temp);
System.arraycopy(chromosome[parent[i+1]],temp+1,childChromosome[i+1],temp+1, n -temp-1);
}else {
childChromosome[i]=chromosome[parent[i]].clone();
childChromosome[i+1]=chromosome[parent[i+1]].clone();
}
}else {
childChromosome[i]=chromosome[parent[i]].clone();
}
}
//基因突变
for (int i = 0; i < populationNum; i++) {
for (int j = 0; j < n; j++) {
if (Math.random()<variationRate){
if (childChromosome[i][j]==0){
childChromosome[i][j]=1;
}else {
childChromosome[i][j]=0;
}
}
}
}
//更新下一代染色体
for (int i = 0; i < populationNum; i++) {
chromosome[i]=childChromosome[i].clone();
}
//更新下一代染色体的适应性
for (int i = 0; i < populationNum; i++) {
subsidy[i]=0;
join[i]=0;
adaptiveness[i][0]=i;
adaptiveness[i][1]=0;
adaptivenessSum=0;
q[i]=new double[n];
z[i]=new double[n];
y[i]=new double[n];
for (int j = 0; j < n; j++) {
if (chromosome[i][j]==1){
double sum = 0;
double threshold1;
for (int k = 0; k < n; k++) {
sum+=chromosome[i][k]*profit[j][k];
}
q[i][j]=sum-c[j];
threshold1 = q[i][j]-r*c[j];
if (threshold1>0){
z[i][j]=threshold1/(1+r);
if (z[i][j]<=mM){
q[i][j]-=z[i][j];
adaptiveness[i][1]+=threshold1/(1+r);
}//else{报错}
}else if (-threshold1<=mM){
y[i][j]=-threshold1;
subsidy[i]+=y[i][j];
q[i][j]+=y[i][j];
}
join[i]++;
}
}
/* if ((double)join[i]/n>=tT){
System.out.println(Arrays.toString(chromosome[i]));
System.out.println(join[i]);
System.out.println((double)join[i]/n);
System.out.println("收费:"+adaptiveness[i][1]);
System.out.println("补贴:"+subsidy[i]);
}*/
if (subsidy[i]<=yY && (double)join[i]/n>=tT){
adaptiveness[i][1]-=subsidy[i];
//System.out.println("收益1:"+adaptiveness[i][1]);
}else {
/*if ((double)join[i]/n>=tT){
System.out.println("收益2:"+adaptiveness[i][1]);
}*/
adaptiveness[i][1]=-mM;
subsidy[i]=0;
}
adaptivenessSum+=adaptiveness[i][1];
}
Arrays.sort(adaptiveness,((o1, o2) -> (int)o2[1]-(int)o1[1]));
currGeneration++;
}
//更新最优值和最优解
if (currGeneration==generationNum){
for (int i = 0; i < populationNum; i++) {
int temp = (int) (Math.random() * populationNum);
if (adaptiveness[temp][1]==adaptiveness[temp+1][1]&&
adaptiveness[temp][1]==adaptiveness[temp+2][1]&&
adaptiveness[temp][1]==adaptiveness[temp+3][1]){
optimalNo=temp;
break;
}
}
}
System.out.print("适应度:[");
for (int i = 0; i < populationNum; i++) {
System.out.print(adaptiveness[i][1]+",");
}
System.out.println("]");
// writingDocuments(bw1,n,chromosome[optimalNo],y[optimalNo],z[optimalNo],q[optimalNo],c,r,adaptiveness[optimalNo][1],subsidy[optimalNo],join[optimalNo]);
}
public static void maxParticipation(int n,double[]c,double[][] profit,double r,double yY,double tT,double mM,BufferedWriter bw1) throws IOException {
//加入企业数量
int join = n;
//0-1变量,表示企业i是否愿意加入平台,1:是,0:否。
int[] x = new int[n];
//0-1变量,表示对企业i是否收费,1:是(收费),0:否(补贴),-1:该企业已退出。
int[] b = new int[n];
//非负连续变量,表示对企业i的补贴金额。
double[] y = new double[n];
//非负连续变量,表示对企业i的收费金额。
double[] z = new double[n];
//连续变量,表示企业i的净收益。
double[] q = new double[n];
/*企业收益-企业收益门槛值,大于0时可以按比例收费,小于0时就是要补贴金额*/
double[] threshold = new double[n];
/*优先级,就是协会对i企业的补贴划算程度,其值=补贴金额-企业i对
其他企业贡献的收益总额。值越大优先级越高。*/
double[] priority = new double[n];
//协会总收益
double associationProfit = 0;
//协会总补贴
double subsidy = 0;
//先假设所有人都加入
for (int i = 0; i < n; i++) {
x[i] = 1;
b[i] = 1;
}
bw1.write(" 求入会企业数最大化:\t\n");
while (true){
//遍历收益矩阵,计算和更新q[i],threshold[i],z[i],b[i],priority[i].
for (int i = 0; i < n; i++) {
//计算q[i]的值
double pi = 0;
for (int j = 0; j < n; j++) {
pi+=x[j]*profit[i][j];
}
q[i]=pi-c[i];
//计算threshold[i]的值
threshold[i]=q[i]-r*c[i];
//如果不需要补贴
if (threshold[i] >= 0 ){
//不用补贴,划算程度设为最大。
priority[i] = mM;
//计算收费金额
z[i]=threshold[i]/(1+r);
if (z[i]<=mM){
//更新数据
q[i]-=z[i];
threshold[i]-=r*z[i];
associationProfit+=z[i];
}
//如果本来要补贴的变成不用补贴,更改标记。
if (b[i]==0){
b[i]=1;
}//如果需要补贴,先检查是否已退出
}else if (x[i]==1){
//补贴标记
b[i]=0;
z[i]=b[i];
//计算企业i的贡献总额
int contribution = 0;
for (int j = 0; j < n; j++) {
contribution+=profit[j][i];
}//计算补贴企业i的划算程度
priority[i]=contribution+threshold[i];
}
}
//寻找优先级最低的企业编号
//工具变量,temp2记录补贴最不划算的企业编号,temp3是划算程度,辅助比较大小。
int temp2 = 0;
double temp3 = mM;
for (int i = 0; i < n; i++) {
//遍历threshold找出需要补贴的企业中最不划算的企业编号
if (b[i]==0 && x[i]==1){
if (priority[i]<temp3){
temp2=i;
temp3=priority[i];
}
//记录补贴额
subsidy-=threshold[i];
}
}
//如果企业补贴额不超上限
if (subsidy<=yY){
//更新协会收益
associationProfit-=subsidy;
break;
/*如果补贴额超了,就让补贴最不划算的一个企业退出
只有加入企业数大于最低比率,才能让企业退出*/
}else if ((double)join/n>tT){
join--;
x[temp2]=0;
}else {
reportErrors(bw1,tT,join,subsidy,yY);
return;
}
//退出一个企业后,协会收费要重新计算,收益归零。
associationProfit=0;
subsidy=0;
}
//最后再更新y[i]
for (int i = 0; i < n; i++) {
if (b[i]==0 && -threshold[i]<=mM && x[i]==1){
y[i]=-threshold[i];
q[i]+=y[i];
}
}
writingDocuments(bw1,n,x,y,z,q,c,r,associationProfit,subsidy,join);
}
private static String interval(double num){
int n = 16;
StringBuilder str = new StringBuilder();
while (Math.abs(num)/10>=1 && n>1){
num/=10;
n-=2;
}
if (num<0){
n--;
}
for (int i = 0; i < n; i++) {
str.append(" ");
}
return str.toString();
}
private static double getDoubleValue(String str) {
double d = 0;
if (str != null && str.length() != 0) {
StringBuilder b = new StringBuilder();
char[] chars = str.toCharArray();
for (char c : chars) {
if (c >= '0' && c <= '9') {
b.append(c);
} else if (c=='.') {
if (b.indexOf(".") != -1 && b.length()!=0) {
break;
} else {
b.append(c);
}
}else if (c=='-'){
if (b.indexOf("-") != -1 && b.length()==0) {
break;
} else if (b.length()==0){
b.append(c);
}
} else {
if (b.length() != 0 ) {
break;
}
}
}
d = Double.parseDouble("".equals(b.toString())?"0.00":b.toString());
}
return d;
}
private static double[] getDoubleArrays(String str,int n) {
double[] d = new double[n];
if (str != null && str.length() != 0) {
int temp1 = 0;
int temp2 = 0;
StringBuilder b = new StringBuilder();
char[] chars = str.toCharArray();
for (char c : chars) {
if (c >= '0' && c <= '9') {
b.append(c);
temp2=0;
} else if (c == '.') {
if (b.indexOf(".") != -1 && b.length() != 0 && temp2==0) {
temp2=1;
} else if (b.length()!=0){
b.append(c);
}
} else if (c == '-') {
if (b.indexOf("-") != -1 && b.length() != 0 && temp2==0) {
temp2=1;
} else if (b.length()==0){
b.append(c);
}
}else if (b.length() != 0 && temp2==0 ) {
temp2=1;
}
if (temp2 == 1 && temp1 < n && !"".equals(b.toString())){
d[temp1] = Double.parseDouble(b.toString());
temp1++;
temp2=0;
b=new StringBuilder();
}
}
if (!"".equals(b.toString())){
d[temp1] = Double.parseDouble(b.toString());
}
}
return d;
}
private static void reportErrors(BufferedWriter bw1,double tT,int join,double subsidy,double yY) throws IOException {
bw1.write(" 输入数据错误:要求的业内企业加入平台的最低比率为" + tT +
"时,补贴总额超预算。\t\n");
bw1.write(" 加入企业数为" + join + ",补贴总额为" + subsidy + ",预算总额为" + yY + "。\t\n");
bw1.write(" 请修改要求业内企业加入平台的最低比率或收益矩阵。\t\n");
}
private static void writingDocuments(BufferedWriter bw1,int n,int[]x,double[]y,double[]z,double[]q,double[]c,double r,
double associationProfit,double subsidy,int join) throws IOException {
bw1.write(" i x y " +
" z q c r\t\n");
for (int i = 0; i < n; i++) {
bw1.write(interval(i+1));
bw1.write(String.format("%d", i+1));
bw1.write(interval(x[i]));
bw1.write(String.format("%d", x[i]));
bw1.write(interval(y[i]));
bw1.write(String.format("%.1f", y[i]));
bw1.write(interval(z[i]));
bw1.write(String.format("%.1f", z[i]));
bw1.write(interval(q[i]));
bw1.write(String.format("%.1f", q[i]));
bw1.write(interval(c[i]));
bw1.write(String.format("%.1f", c[i]));
bw1.write(interval(r));
bw1.write(String.format("%.1f", r)+"\t\n");
}
bw1.write(" 行业内的企业个数:"+n+"\t\n");
bw1.write(" 加入协会的企业数:"+join+"\t\n");
bw1.write(" 协会总收费金额:"+(associationProfit+subsidy)+"\t\n");
bw1.write(" 协会总补贴金额:"+subsidy+"\t\n");
bw1.write(" 协会净收益金额:"+associationProfit+"\t\n");
bw1.flush();
}
}