启发方法
柔性作业车间问题的启发求解方法如【柔性作业车间调度问题-启发求解方法】,主要使用了简单的最早开始加工时间和最早加工结束时间启发策略,虽然能够得到可行的加工方案,但是仍然存在可进一步改进的方向。
问题描述
柔性作业车间问题可描述为:每一待加工工件包含一道或一道以上工序,每个工件的工序顺序都是已知的,每道工序可以在一台及以上的机器上完成加工, 加工的时间会因为所选择的加工机器不同而变得不同。 调度方案需要确定工序的加工顺序和机器的选择,从而使得整个调度系统的各指标达到最优。
加工过程需满足以下条件:
(1)工件工序只能在可加工设备上进行加工
(2)一台设备同一时间段只能对一个工件工序进行加工
(3)工件工序开始加工后无法停止
(4)工件下一工序的开始时间大于等于上一工序的结束时间,即工件工序具备加工次序
工件数据
仿真数据来源于文献:[1]高尚,李荣平.改进NSGA-Ⅱ求解多目标柔性作业车间调度问题[J].河北企业,2022(04):70-72.DOI:10.19885/j.cnki.hbqy.2022.04.021.
遗传算法求解步骤
(1)初始化种群-随机生成可行方案
(2)初始化种群最优适应值和最优个体-个体解码
(3)个体选择-轮盘赌概率选择策略
(4)个体交叉-POX交叉方式
(5)个体变异-交换变异
(6)子代生成-父代和变异种群竞争
(7)更新种群最佳适应值和最优个体
个体编码
采用工序、设备双层编码的方式分别用于解决工序排列及设备分配问题,编码过程如下:
以4工件(1:2;2:2;3:1;4:3)8个工序【1,1,2,2,3,4,4,4】为例,详细的工序编码过程如下:
(1)生成随机数组
(2)数组排序
(3)根据数组排序,选择工序并生成个体
(4)工序编码结果
个体基因位:表示待加工的工件编号
基因位所处位置:表示工件的加工顺序
工件次数:表示加工该工件的第XX个工序
根据(3)编码结果,首先加工工件4的第1道工序,紧接着工件4的第2道工序,…;整体加工顺序:4_1->4_2->3_1->1_1->2_1->4_3->2_2->1_2
假定各个工序可加工的设备编号如下:
1_1:1,3,4
1_2:3
2_1:2,4
2_2:1,3,4
3_1:1,2
4_1:1,2
4_2:3,4
4_3:2,3,4
根据工序编码结果,详细的设备编码过程是根据同基因位的工序的可用设备长度,随机生成[0,可用设备集合长度-1]之间的随机数,该随机数表示使用该工序可用设备集合中的索引位置,而不是设备编号;
例如对于1_1工序,随机数在[0,1,2]中产生。
实现代码如下:
//种群初始化-个体编码
private void initPop(){
for(int i=0;i<popNum;i++){
int[] processRamdomIndex=processRandom();
for(int j=0;j<processNum;j++){
processCode[i][j]=processList.get(processRamdomIndex[j]-1);
}
int[] deviceRandomIndex=deviceRandom(processCode[i]);
for(int j=0;j<processNum;j++){
deviceCode[i][j]=deviceRandomIndex[j];
}
}
}
//产生个体长度的随机数-工序
private int[] processRandom(){
int[] processSort=new int[processNum];
double[] processRandomValue=new double[processNum];
Random random = new Random();
for(int i=0;i<processNum;i++){
processRandomValue[i]=random.nextDouble(10);
processSort[i]=i+1;
}
//冒泡排序
for(int i=1;i<processRandomValue.length;i++){
for(int j=0;j<processRandomValue.length-i;j++){
if(processRandomValue[j]>processRandomValue[j+1]){
double temp=processRandomValue[j+1];
int tempIndex=processSort[j+1];
processRandomValue[j+1]=processRandomValue[j];
processSort[j+1]=processSort[j];
processRandomValue[j]=temp;
processSort[j]=tempIndex;
}
}
}
return processSort;
}
//产生个体长度的随机数-设备索引
private int[] deviceRandom(int[] processIndex){
int[] deviceRandomValue=new int[processNum];
int[] workList=new int[data.workId.length];
Random random = new Random();
int count=0;
for(int i=0;i<processNum;i++){
deviceRandomValue[count++]=random.nextInt(processDevice.get(processIndex[i]-1).get(workList[processIndex[i]-1]).size());
workList[processIndex[i]-1]+=1;
}
return deviceRandomValue;
}
个体解码
根据工序编码和设备编码,依据最早开始加工时间的贪婪策略,将工件工序分配到设备上。
实现代码如下:
//个体解码
private double greedyDecode(int[] processPop,int[] devicePop,boolean rstType){
//清空列表
workResult=new ArrayList<ArrayList<shopStructure>>();
for(int i=0;i<data.deviceId.length;i++){
ArrayList<shopStructure> workResultTemp=new ArrayList<shopStructure>();
workResult.add(workResultTemp);
}
//记录开始和结束时间
double[][] startTime=new double[data.workId.length][6];
double[][] endTime=new double[data.workId.length][6];
for(int i=0;i<startTime.length;i++){
for(int j=0;j<6;j++){
startTime[i][j]=-1;
endTime[i][j]=-1;
}
}
//记录工件使用次数-工序
int[] workList=new int[data.workId.length];
//分配工序到设备
for(int i=0;i<processPop.length;i++){
int deviceIndex=processDevice.get(processPop[i]-1).get(workList[processPop[i]-1]).get(devicePop[i]);
double deviceTime = Double.MAX_VALUE;
if(workResult.get(deviceIndex-1).size()==0){
if(workList[processPop[i]-1]==0){
deviceTime=0;
}
else{
deviceTime = endTime[processPop[i]-1][workList[processPop[i]-1]-1]+1;
}
}
else{
//设备已存在分配的工序
//第一个工序分配
if(workList[processPop[i]-1]==0){
deviceTime=workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime+1;
}
else{
if (workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime >= endTime[processPop[i]-1][workList[processPop[i]-1]-1]) {
deviceTime = workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime+1;
}
if (workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime < endTime[processPop[i]-1][workList[processPop[i]-1]-1]) {
deviceTime = endTime[processPop[i]-1][workList[processPop[i]-1]-1]+1;
}
}
}
//更新工件信息
shop.workId = processPop[i];
shop.workProcess = workList[processPop[i]-1]+1;
shop.deviceId = deviceIndex;
shop.startTime = deviceTime;
startTime[processPop[i]-1][workList[processPop[i]-1]] = shop.startTime;
shop.endTime = shop.startTime + data.ProcessTime[processPop[i]-1][workList[processPop[i]-1]][deviceIndex-1];
endTime[processPop[i]-1][workList[processPop[i]-1]] = shop.endTime;
workResult.get(deviceIndex-1).add(shop.clone());
workList[processPop[i]-1]+=1;
}
//计算最大完工时间
double maxTime=maxEndTime(endTime);
if(rstType)printResult(workResult,endTime);
return maxTime;
}
//计算最大完工时间
private double maxEndTime(double[][] endTime){
double maxTime=0;
double[] endTimeList=new double[data.workId.length];
for(int i=0;i<endTime.length;i++){
endTimeList[i]=getMax(endTime[i]);
}
maxTime=getMax(endTimeList);
return maxTime;
}
适应值计算
//计算个体适应值
private double fitnessPop(int[] processPop,int[] devicePop,boolean rstType){
double fitness=0;
fitness=greedyDecode(processPop,devicePop,rstType);
return fitness;
}
初始最优个体
//初始最优个体与适应值
private void initFitness(){
for(int i=0;i<processCode.length;i++){
double temp=fitnessPop(processCode[i],deviceCode[i],false);
if(temp<targetBest){
targetBest=temp;
processBest=processCode[i].clone();
deviceBest=deviceCode[i].clone();
}
}
}
个体变异
变异操作一方面是对个体施加轻微的扰动,有利于进行交叉;一方面是对交叉个体实施较大的扰动,以便于在更大的范围内产生新个体并使得个体跳出局部收敛状态。在进行变异操作时,若mutateType=true表示进行扰动,期间只对个体的两个基因位进行交换;否则表示进行常规的变异操作,变异的位数为个体长度的0.2。
在实施变异操作过程中,变异位置为偶数个随机生成的[0,个体长度-1]的随机数。
针对个体的工序,互换第i和i+1个基因位上的工件编号,直到完成所有基因位的变异(i=i+2)。
针对个体的设备,根据变异后的个体工序编码,随机产生相应的可用设备索引。
实现代码如下:
//个体变异:工序随机交换指定偶数位;设备随机选取
private int[][] mutationPop(int[] processPop,int[] devicePop,boolean mutateType){
int[][] newPop=new int[2][processPop.length];
newPop[0]=processPop.clone();
newPop[1]=devicePop.clone();
Random random = new Random();
int mutateNum;
int[] processIndex;
//交叉前变异
if(mutateType){
mutateNum=2;
processIndex=new int[mutateNum];
}
//交叉后变异
else{
//变异位数
mutateNum=processPop.length/5;
if(mutateNum%2!=0)mutateNum-=1;
processIndex=new int[mutateNum];
}
//工序变异位置
for(int i=0;i<processIndex.length;i++){
processIndex[i]=random.nextInt(newPop[0].length);
}
//工序变异
for(int i=0;i<processIndex.length;i+=2){
int temp=newPop[0][processIndex[i]];
newPop[0][processIndex[i]]=newPop[0][processIndex[i+1]];
newPop[0][processIndex[i+1]]=temp;
}
//设备变异位置
for(int i=0;i<processIndex.length;i++){
//确定工序
int count=0;
for(int j=0;j<newPop[0].length;j++){
if(newPop[0][j]==newPop[0][processIndex[i]]){
newPop[1][j]=random.nextInt(processDevice.get(newPop[0][processIndex[i]]-1).get(count).size());
count+=1;
}
}
}
return newPop;
}
个体交叉
交叉操作是对个体信息进行交换,有利于产生更好的个体。在进行交叉时,采用POX交叉方式,如下:
红色位置表示个体对应的交叉位置-交叉点,需满足交叉点在个体1和个体2的工件编号中保持一致;例如上述个体1的交叉点为:4,1,4;而个体2的交叉点为:4,4,1。区别仅是位置不同。
(1)以个体1的交叉点位为基础,将个体2的非交叉点位的基因填充到个体1
(2)以个体2的交叉点位为基础,将个体1的非交叉点位的基因填充到个体2
实现代码如下:
//轮盘赌策略-计算选择概率
private double[] rouletteStrategy(int[][] processCodeChild,int[][] deviceCodeChild){
double[] selectedProb=new double[popNum];
double fitnessSum=0;
//计算个体适应值
for(int i=0;i<popNum;i++){
selectedProb[i]=fitnessPop(processCodeChild[i],deviceCodeChild[i],false);
fitnessSum+=selectedProb[i];
}
//反差
double selectedSum=0;
for(int i=0;i<popNum;i++){
selectedProb[i]=fitnessSum-selectedProb[i];
selectedSum+=selectedProb[i];
}
//计算累积概率
double[] selectedProbTemp=selectedProb.clone();
for(int i=0;i<popNum;i++){
if(i==0)selectedProb[i]=selectedProbTemp[i]/selectedSum;
else selectedProb[i]=(selectedProbTemp[i]/selectedSum)+selectedProb[i-1];
}
return selectedProb;
}
//个体选择
private int[] selectPop(double[] selectedProb){
int[] selectedIndex=new int[2];
Random random = new Random();
for(int i=0;i<selectedIndex.length;i++){
double temp=random.nextDouble(0,1);
//找到位置索引
for(int j=0;j<selectedProb.length;j++){
if(temp<=selectedProb[j]){
selectedIndex[i]=j;
break;
}
}
}
return selectedIndex;
}
//个体交叉
private int[][] crossPop(int[] selectedIndex){
int[][] crossResult=new int[4][processNum];
//随机交叉位置
int crossNum=processNum/5;
if(crossNum<=0)crossNum=1;
int[] crossIndex=new int[crossNum];
int[] arrTemp=new int[processNum];
for(int i=0;i<arrTemp.length;i++){
arrTemp[i]=i;
}
shuffle(arrTemp);
for(int i=0;i<crossIndex.length;i++){
crossIndex[i]=arrTemp[i];
}
//找到另一个体上的交叉位置
int[] anotherCrossIndex=new int[crossNum];
for(int i=0;i<anotherCrossIndex.length;i++){anotherCrossIndex[i]=-1;}
for(int i=0;i<crossIndex.length;i++){
for(int j=0;j<processCode[selectedIndex[1]].length;j++){
if(processCode[selectedIndex[1]][j]==processCode[selectedIndex[0]][crossIndex[i]]){
//是否已经添加过
boolean appendType=false;
for(int k=0;k<anotherCrossIndex.length;k++){
if(anotherCrossIndex[k]==j){
appendType=true;
break;
}
}
if(!appendType){
anotherCrossIndex[i]=j;
}
}
}
}
//交叉
for(int i=0;i<selectedIndex.length;i++){
int count=0;
for(int j=0;j<processNum;j++){
if(i==0){
if(judgeExist(crossIndex,j)){
crossResult[0][j]=processCode[selectedIndex[i]][j];
crossResult[2][j]=deviceCode[selectedIndex[i]][j];
}
else{
//另一个体当中选择第一个不在交叉位置的索引
while(true){
if(!judgeExist(anotherCrossIndex,count)){
break;
}
else{
count++;
}
}
crossResult[0][j]=processCode[selectedIndex[1-i]][count];
crossResult[2][j]=deviceCode[selectedIndex[1-i]][count];
count++;
}
}
else{
if(judgeExist(anotherCrossIndex,j)){
crossResult[1][j]=processCode[selectedIndex[i]][j];
crossResult[3][j]=deviceCode[selectedIndex[i]][j];
}
else{
//另一个体当中选择第一个不在交叉位置的索引
while(true){
if(!judgeExist(crossIndex,count)){
break;
}
else{
count++;
}
}
crossResult[1][j]=processCode[selectedIndex[1-i]][count];
crossResult[3][j]=deviceCode[selectedIndex[1-i]][count];
count++;
}
}
}
}
//校验设备分配-如果超出索引,则随机分配;
crossResult[2]=deviceCheck(crossResult[0].clone(),crossResult[2].clone());
crossResult[3]=deviceCheck(crossResult[1].clone(),crossResult[3].clone());
return crossResult;
}
设备校验
根据交叉结果,由于工件位置发生变化,原位置处代表的工序在交叉后的个体位置代表的工序有所不同,导致部分工件工序的可用设备出现异常,即使用不可用设备对工件工序进行了加工,在这种情况下,需要对个体的设备进行校验。与交叉操作相同,变异操作同样也需要进行设备校验。
设备校验的原则是依次检验个体的工序和设备编码,若该设备编码不满足对应位置的工件工序,则对该工件工序随机产生一个新的可用设备索引。
实现代码如下:
//设备校验
private int[] deviceCheck(int[] processPop,int[] devicePop){
int[] checkResult=new int[devicePop.length];
int[] workList=new int[data.workId.length];
Random random = new Random();
for(int i=0;i<devicePop.length;i++){
int deviceIndexLength=processDevice.get(processPop[i]-1).get(workList[processPop[i]-1]).size();
if(devicePop[i]<deviceIndexLength){
checkResult[i]=devicePop[i];
}
else{
checkResult[i]=random.nextInt(deviceIndexLength);
}
workList[processPop[i]-1]+=1;
}
return checkResult;
}
子代生成
通过父代种群和变异种群,选择前N个适应值最小的个体组成新的迭代种群。
实现代码如下:
//子代生成
private void generateChild(int[][] processCode,int[][] deviceCode,int[][] processCodeChild,int[][] deviceCodeChild){
//计算原种群适应值
double[] targetValue=new double[processCode.length+processCodeChild.length];
int[] targetIndex=new int[processCode.length+processCodeChild.length];
for(int i=0;i<processCode.length;i++){
targetValue[i]=fitnessPop(processCode[i].clone(),deviceCode[i].clone(),false);
targetIndex[i]=i;
}
for(int i=0;i<processCodeChild.length;i++){
targetValue[i+processCode.length]=fitnessPop(processCodeChild[i].clone(),deviceCodeChild[i].clone(),false);
targetIndex[i+processCode.length]=i+processCode.length;
}
//排序
for(int i=1;i<targetValue.length;i++){
for(int j=0;j<targetValue.length-i;j++){
if(targetValue[j]>targetValue[j+1]){
double temp=targetValue[j+1];
int tempIndex=targetIndex[j+1];
targetValue[j+1]=targetValue[j];
targetIndex[j+1]=targetIndex[j];
targetValue[j]=temp;
targetIndex[j]=tempIndex;
}
}
}
//生成子代
for(int i=0;i<this.processCode.length;i++){
if(targetIndex[i]<processCode.length){
this.processCode[i]=processCode[targetIndex[i]].clone();
this.deviceCode[i]=deviceCode[targetIndex[i]].clone();
}
else{
this.processCode[i]=processCodeChild[targetIndex[i]-processCode.length].clone();
this.deviceCode[i]=deviceCodeChild[targetIndex[i]-processCode.length].clone();
}
}
}
更新最优个体
//更新最优个体与适应值
private void updateFitness(){
for(int i=0;i<processCode.length;i++){
double temp=fitnessPop(processCode[i],deviceCode[i],false);
if(temp<targetBest){
targetBest=temp;
processBest=processCode[i].clone();
deviceBest=deviceCode[i].clone();
}
}
}
算法流程
private void GAMethod(){
//初始化
initPop();
//初始最优个体与适应值
initFitness();
System.out.println("最优个体:"+targetBest);
for(int i=0;i<processNum;i++){
System.out.print(processBest[i]+"\t");
}
System.out.println();
for(int i=0;i<processNum;i++){
System.out.print(deviceBest[i]+"\t");
}
//迭代记录
int iter=0;
while(iter<ITER){
//扰动
int[][] processCodeTemp=processCode.clone();
int[][] deviceCodeTemp=deviceCode.clone();
for(int i=0;i<popNum;i++){
int[][] mutatePopTemp=mutationPop(processCode[i].clone(),deviceCode[i].clone(),true);
processCodeTemp[i]=mutatePopTemp[0].clone();
deviceCodeTemp[i]=mutatePopTemp[1].clone();
}
//交叉
int[][] processCodeChild=processCode.clone();
int[][] deviceCodeChild=deviceCode.clone();
double[] selectedProb=rouletteStrategy(processCodeTemp,deviceCodeTemp);
int crossCount=0;
for(int i=0;i<processCode.length/2;i++){
int[] selectedIndex= selectPop(selectedProb);
int[][] crossResult=crossPop(selectedIndex);
processCodeChild[crossCount]=crossResult[0].clone();
deviceCodeChild[crossCount]=crossResult[2].clone();
crossCount++;
processCodeChild[crossCount]=crossResult[1].clone();
deviceCodeChild[crossCount]=crossResult[3].clone();
crossCount++;
}
//变异
for(int i=0;i<popNum;i++){
int[][] mutatePopTemp=mutationPop(processCodeChild[i].clone(),deviceCodeChild[i].clone(),false);
processCodeChild[i]=mutatePopTemp[0].clone();
deviceCodeChild[i]=mutatePopTemp[1].clone();
}
//选择
generateChild(processCode.clone(),deviceCode.clone(),processCodeChild.clone(),deviceCodeChild.clone());
//更新
updateFitness();
iter++;
}
System.out.println("最优个体:"+targetBest);
for(int i=0;i<processNum;i++){
System.out.print(processBest[i]+"\t");
}
System.out.println();
for(int i=0;i<processNum;i++){
System.out.print(deviceBest[i]+"\t");
}
System.out.println();
greedyDecode(processBest,deviceBest,true);
}
求解结果
结果对比
代码实现方案结果:
所得方案的各个工件的最大完工时间为67,且各个工件的完工时间均满足交货期限制,延期时间为0。
[1]高尚,李荣平.改进NSGA-Ⅱ求解多目标柔性作业车间调度问题[J]论文结果的最大完工时间为69,延期时间为0。
改进方向
(1)多目标求解-非支配方法
(2)变异和交叉概率-自适应变异概率,交叉概率
(3)邻域搜索策略
(4)混合智能算法策略
完整代码
由于代码使用涉及【柔性作业车间调度问题-启发求解方法】部分函数,可以在该博客进行查询或者联系作者进行交流,在这里仅给出遗传算法的求解代码。
//遗传算法求解
GAAlgorithm ga=new GAAlgorithm();
class GAAlgorithm{
Data data;
//工件
shopStructure shop;
//种群个数
int popNum;
//工序个数
int processNum;
//迭代次数
int ITER;
//工序列表
ArrayList<Integer>processList;
//工序编码
int[][] processCode;
//设备编码
int[][] deviceCode;
//工序可用设备编码
ArrayList<ArrayList<ArrayList<Integer>>> processDevice;
//最优工序个体
int[] processBest;
//最优设备个体
int[] deviceBest;
//最优目标值
double targetBest;
//调度结果
ArrayList<ArrayList<shopStructure>>workResult;
private GAAlgorithm(){
data=new Data();
//初始化工件类
shop=new shopStructure();
//种群个数
popNum=200;
processNum=0;
ITER=500;
for(int i=0;i<data.workProcess.length;i++){
processNum+=data.workProcess[i].length;
}
//工序编码
processCode=new int[popNum][processNum];
processList=new ArrayList<>();
for(int i=0;i<data.workProcess.length;i++){
for(int j=0;j<data.workProcess[i].length;j++){
processList.add(i+1);
}
}
//设备编码
deviceCode=new int[popNum][processNum];
//工序可用设备编码
processDevice=new ArrayList<>();
for(int i=0;i<data.ProcessTime.length;i++){
ArrayList<ArrayList<Integer>>processDevice1=new ArrayList<>();
for(int j=0;j<data.ProcessTime[i].length;j++){
double[] deviceTimeList=new double[data.deviceId.length];
int[] deviceTimeIndex=new int[data.deviceId.length];
for(int k=0;k<data.ProcessTime[i][j].length;k++){
deviceTimeList[k]=data.ProcessTime[i][j][k];
deviceTimeIndex[k]=k;
}
//由小到大排序
for(int ii=1;ii<deviceTimeList.length;ii++){
for(int jj=0;jj<deviceTimeList.length-ii;jj++){
if(deviceTimeList[jj]>deviceTimeList[jj+1]){
double temp=deviceTimeList[jj+1];
int tempIndex=deviceTimeIndex[jj+1];
deviceTimeList[jj+1]=deviceTimeList[jj];
deviceTimeIndex[jj+1]=deviceTimeIndex[jj];
deviceTimeList[jj]=temp;
deviceTimeIndex[jj]=tempIndex;
}
}
}
ArrayList<Integer>processDevice2=new ArrayList<>();
for(int k=0;k<data.ProcessTime[i][j].length;k++){
if(deviceTimeList[k]!=Double.MAX_VALUE){
processDevice2.add(deviceTimeIndex[k]+1);
}
}
processDevice1.add(processDevice2);
}
processDevice.add(processDevice1);
}
//最优工序个体
processBest=new int[processNum];
//最优设备个体
deviceBest=new int[processNum];
//最优目标值
targetBest=Double.MAX_VALUE;
//初始化调度结果
workResult=new ArrayList<ArrayList<shopStructure>>();
for(int i=0;i<data.deviceId.length;i++){
ArrayList<shopStructure> workResultTemp=new ArrayList<shopStructure>();
workResult.add(workResultTemp);
}
}
//种群初始化-个体编码
private void initPop(){
for(int i=0;i<popNum;i++){
int[] processRamdomIndex=processRandom();
for(int j=0;j<processNum;j++){
processCode[i][j]=processList.get(processRamdomIndex[j]-1);
}
int[] deviceRandomIndex=deviceRandom(processCode[i]);
for(int j=0;j<processNum;j++){
deviceCode[i][j]=deviceRandomIndex[j];
}
}
}
//初始最优个体与适应值
private void initFitness(){
for(int i=0;i<processCode.length;i++){
double temp=fitnessPop(processCode[i],deviceCode[i],false);
if(temp<targetBest){
targetBest=temp;
processBest=processCode[i].clone();
deviceBest=deviceCode[i].clone();
}
}
}
//个体变异:工序随机交换指定偶数位;设备随机选取
private int[][] mutationPop(int[] processPop,int[] devicePop,boolean mutateType){
int[][] newPop=new int[2][processPop.length];
newPop[0]=processPop.clone();
newPop[1]=devicePop.clone();
Random random = new Random();
int mutateNum;
int[] processIndex;
//交叉前变异
if(mutateType){
mutateNum=2;
processIndex=new int[mutateNum];
}
//交叉后变异
else{
//变异位数
mutateNum=processPop.length/5;
if(mutateNum%2!=0)mutateNum-=1;
processIndex=new int[mutateNum];
}
//工序变异位置
for(int i=0;i<processIndex.length;i++){
processIndex[i]=random.nextInt(newPop[0].length);
}
// System.out.println();
// System.out.println("工序变异位置");
// for(int i=0;i<processIndex.length;i++){
// System.out.print((processIndex[i]+1)+"\t");
// }
// System.out.println();
//工序变异
for(int i=0;i<processIndex.length;i+=2){
int temp=newPop[0][processIndex[i]];
newPop[0][processIndex[i]]=newPop[0][processIndex[i+1]];
newPop[0][processIndex[i+1]]=temp;
}
// System.out.println("工序变异结果");
// for(int j=0;j<newPop[0].length;j++){
// System.out.print(newPop[0][j]+"\t");
// }
// System.out.println();
//设备变异位置
for(int i=0;i<processIndex.length;i++){
//确定工序
int count=0;
for(int j=0;j<newPop[0].length;j++){
if(newPop[0][j]==newPop[0][processIndex[i]]){
newPop[1][j]=random.nextInt(processDevice.get(newPop[0][processIndex[i]]-1).get(count).size());
count+=1;
}
}
}
// System.out.println("设备变异结果");
// for(int i=0;i<newPop[1].length;i++){
// System.out.print(newPop[1][i]+"\t");
// }
return newPop;
}
//轮盘赌策略-计算选择概率
private double[] rouletteStrategy(int[][] processCodeChild,int[][] deviceCodeChild){
double[] selectedProb=new double[popNum];
double fitnessSum=0;
//计算个体适应值
for(int i=0;i<popNum;i++){
selectedProb[i]=fitnessPop(processCodeChild[i],deviceCodeChild[i],false);
fitnessSum+=selectedProb[i];
}
//反差
double selectedSum=0;
for(int i=0;i<popNum;i++){
selectedProb[i]=fitnessSum-selectedProb[i];
selectedSum+=selectedProb[i];
}
//计算累积概率
double[] selectedProbTemp=selectedProb.clone();
for(int i=0;i<popNum;i++){
if(i==0)selectedProb[i]=selectedProbTemp[i]/selectedSum;
else selectedProb[i]=(selectedProbTemp[i]/selectedSum)+selectedProb[i-1];
}
return selectedProb;
}
//个体选择
private int[] selectPop(double[] selectedProb){
int[] selectedIndex=new int[2];
Random random = new Random();
for(int i=0;i<selectedIndex.length;i++){
double temp=random.nextDouble(0,1);
//找到位置索引
for(int j=0;j<selectedProb.length;j++){
if(temp<=selectedProb[j]){
selectedIndex[i]=j;
break;
}
}
}
return selectedIndex;
}
//个体交叉
private int[][] crossPop(int[] selectedIndex){
int[][] crossResult=new int[4][processNum];
//随机交叉位置
int crossNum=processNum/5;
if(crossNum<=0)crossNum=1;
int[] crossIndex=new int[crossNum];
int[] arrTemp=new int[processNum];
for(int i=0;i<arrTemp.length;i++){
arrTemp[i]=i;
}
shuffle(arrTemp);
for(int i=0;i<crossIndex.length;i++){
crossIndex[i]=arrTemp[i];
}
// System.out.println("个体1交叉位置:");
// for(int i=0;i<crossIndex.length;i++){
// System.out.print(crossIndex[i]+"\t");
// }
// System.out.println();
//找到另一个体上的交叉位置
int[] anotherCrossIndex=new int[crossNum];
for(int i=0;i<anotherCrossIndex.length;i++){anotherCrossIndex[i]=-1;}
for(int i=0;i<crossIndex.length;i++){
for(int j=0;j<processCode[selectedIndex[1]].length;j++){
if(processCode[selectedIndex[1]][j]==processCode[selectedIndex[0]][crossIndex[i]]){
//是否已经添加过
boolean appendType=false;
for(int k=0;k<anotherCrossIndex.length;k++){
if(anotherCrossIndex[k]==j){
appendType=true;
break;
}
}
if(!appendType){
anotherCrossIndex[i]=j;
}
}
}
}
// System.out.println("个体2交叉位置:");
// for(int i=0;i<anotherCrossIndex.length;i++){
// System.out.print(anotherCrossIndex[i]+"\t");
// }
// System.out.println();
//交叉
for(int i=0;i<selectedIndex.length;i++){
int count=0;
for(int j=0;j<processNum;j++){
if(i==0){
if(judgeExist(crossIndex,j)){
crossResult[0][j]=processCode[selectedIndex[i]][j];
crossResult[2][j]=deviceCode[selectedIndex[i]][j];
}
else{
//另一个体当中选择第一个不在交叉位置的索引
while(true){
if(!judgeExist(anotherCrossIndex,count)){
break;
}
else{
count++;
}
}
crossResult[0][j]=processCode[selectedIndex[1-i]][count];
crossResult[2][j]=deviceCode[selectedIndex[1-i]][count];
count++;
}
}
else{
if(judgeExist(anotherCrossIndex,j)){
crossResult[1][j]=processCode[selectedIndex[i]][j];
crossResult[3][j]=deviceCode[selectedIndex[i]][j];
}
else{
//另一个体当中选择第一个不在交叉位置的索引
while(true){
if(!judgeExist(crossIndex,count)){
break;
}
else{
count++;
}
}
crossResult[1][j]=processCode[selectedIndex[1-i]][count];
crossResult[3][j]=deviceCode[selectedIndex[1-i]][count];
count++;
}
}
}
}
//校验设备分配-如果超出索引,则随机分配;
crossResult[2]=deviceCheck(crossResult[0].clone(),crossResult[2].clone());
crossResult[3]=deviceCheck(crossResult[1].clone(),crossResult[3].clone());
return crossResult;
}
//子代生成
private void generateChild(int[][] processCode,int[][] deviceCode,int[][] processCodeChild,int[][] deviceCodeChild){
//计算原种群适应值
double[] targetValue=new double[processCode.length+processCodeChild.length];
int[] targetIndex=new int[processCode.length+processCodeChild.length];
for(int i=0;i<processCode.length;i++){
targetValue[i]=fitnessPop(processCode[i].clone(),deviceCode[i].clone(),false);
targetIndex[i]=i;
}
for(int i=0;i<processCodeChild.length;i++){
targetValue[i+processCode.length]=fitnessPop(processCodeChild[i].clone(),deviceCodeChild[i].clone(),false);
targetIndex[i+processCode.length]=i+processCode.length;
}
//排序
for(int i=1;i<targetValue.length;i++){
for(int j=0;j<targetValue.length-i;j++){
if(targetValue[j]>targetValue[j+1]){
double temp=targetValue[j+1];
int tempIndex=targetIndex[j+1];
targetValue[j+1]=targetValue[j];
targetIndex[j+1]=targetIndex[j];
targetValue[j]=temp;
targetIndex[j]=tempIndex;
}
}
}
//生成子代
for(int i=0;i<this.processCode.length;i++){
if(targetIndex[i]<processCode.length){
this.processCode[i]=processCode[targetIndex[i]].clone();
this.deviceCode[i]=deviceCode[targetIndex[i]].clone();
}
else{
this.processCode[i]=processCodeChild[targetIndex[i]-processCode.length].clone();
this.deviceCode[i]=deviceCodeChild[targetIndex[i]-processCode.length].clone();
}
}
}
//更新最优个体与适应值
private void updateFitness(){
for(int i=0;i<processCode.length;i++){
double temp=fitnessPop(processCode[i],deviceCode[i],false);
if(temp<targetBest){
targetBest=temp;
processBest=processCode[i].clone();
deviceBest=deviceCode[i].clone();
}
}
}
//判断是否存在
private boolean judgeExist(int[] arr,int element){
boolean existType=false;
for(int i=0;i<arr.length;i++){
if(arr[i]==element){
existType=true;
break;
}
}
return existType;
}
//计算个体适应值
private double fitnessPop(int[] processPop,int[] devicePop,boolean rstType){
double fitness=0;
fitness=greedyDecode(processPop,devicePop,rstType);
return fitness;
}
//个体解码
private double greedyDecode(int[] processPop,int[] devicePop,boolean rstType){
//清空列表
workResult=new ArrayList<ArrayList<shopStructure>>();
for(int i=0;i<data.deviceId.length;i++){
ArrayList<shopStructure> workResultTemp=new ArrayList<shopStructure>();
workResult.add(workResultTemp);
}
// System.out.println("解码个体");
// for(int i=0;i<processPop.length;i++){
// System.out.print(processPop[i]+"\t");
// }
// System.out.println();
// for(int i=0;i<devicePop.length;i++){
// System.out.print(devicePop[i]+"\t");
// }
// System.out.println();
//记录开始和结束时间
double[][] startTime=new double[data.workId.length][6];
double[][] endTime=new double[data.workId.length][6];
for(int i=0;i<startTime.length;i++){
for(int j=0;j<6;j++){
startTime[i][j]=-1;
endTime[i][j]=-1;
}
}
//记录工件使用次数-工序
int[] workList=new int[data.workId.length];
//分配工序到设备
for(int i=0;i<processPop.length;i++){
// System.out.println("工序:");
// for(int ii=0;ii<workList.length;ii++){
// System.out.print(workList[ii]+"\t");
// }
// System.out.println();
int deviceIndex=processDevice.get(processPop[i]-1).get(workList[processPop[i]-1]).get(devicePop[i]);
double deviceTime = Double.MAX_VALUE;
if(workResult.get(deviceIndex-1).size()==0){
if(workList[processPop[i]-1]==0){
deviceTime=0;
}
else{
deviceTime = endTime[processPop[i]-1][workList[processPop[i]-1]-1]+1;
}
}
else{
//设备已存在分配的工序
//第一个工序分配
if(workList[processPop[i]-1]==0){
deviceTime=workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime+1;
}
else{
if (workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime >= endTime[processPop[i]-1][workList[processPop[i]-1]-1]) {
deviceTime = workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime+1;
}
if (workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime < endTime[processPop[i]-1][workList[processPop[i]-1]-1]) {
deviceTime = endTime[processPop[i]-1][workList[processPop[i]-1]-1]+1;
}
}
}
//更新工件信息
shop.workId = processPop[i];
shop.workProcess = workList[processPop[i]-1]+1;
shop.deviceId = deviceIndex;
shop.startTime = deviceTime;
startTime[processPop[i]-1][workList[processPop[i]-1]] = shop.startTime;
shop.endTime = shop.startTime + data.ProcessTime[processPop[i]-1][workList[processPop[i]-1]][deviceIndex-1];
endTime[processPop[i]-1][workList[processPop[i]-1]] = shop.endTime;
workResult.get(deviceIndex-1).add(shop.clone());
workList[processPop[i]-1]+=1;
}
//计算最大完工时间
double maxTime=maxEndTime(endTime);
if(rstType)printResult(workResult,endTime);
return maxTime;
}
//计算最大完工时间
private double maxEndTime(double[][] endTime){
double maxTime=0;
double[] endTimeList=new double[data.workId.length];
for(int i=0;i<endTime.length;i++){
endTimeList[i]=getMax(endTime[i]);
}
maxTime=getMax(endTimeList);
return maxTime;
}
//产生个体长度的随机数-工序
private int[] processRandom(){
int[] processSort=new int[processNum];
double[] processRandomValue=new double[processNum];
Random random = new Random();
for(int i=0;i<processNum;i++){
processRandomValue[i]=random.nextDouble(10);
processSort[i]=i+1;
}
//冒泡排序
for(int i=1;i<processRandomValue.length;i++){
for(int j=0;j<processRandomValue.length-i;j++){
if(processRandomValue[j]>processRandomValue[j+1]){
double temp=processRandomValue[j+1];
int tempIndex=processSort[j+1];
processRandomValue[j+1]=processRandomValue[j];
processSort[j+1]=processSort[j];
processRandomValue[j]=temp;
processSort[j]=tempIndex;
}
}
}
return processSort;
}
//产生个体长度的随机数-设备索引
private int[] deviceRandom(int[] processIndex){
int[] deviceRandomValue=new int[processNum];
int[] workList=new int[data.workId.length];
Random random = new Random();
int count=0;
for(int i=0;i<processNum;i++){
deviceRandomValue[count++]=random.nextInt(processDevice.get(processIndex[i]-1).get(workList[processIndex[i]-1]).size());
workList[processIndex[i]-1]+=1;
}
return deviceRandomValue;
}
//设备校验
private int[] deviceCheck(int[] processPop,int[] devicePop){
int[] checkResult=new int[devicePop.length];
int[] workList=new int[data.workId.length];
Random random = new Random();
for(int i=0;i<devicePop.length;i++){
int deviceIndexLength=processDevice.get(processPop[i]-1).get(workList[processPop[i]-1]).size();
if(devicePop[i]<deviceIndexLength){
checkResult[i]=devicePop[i];
}
else{
checkResult[i]=random.nextInt(deviceIndexLength);
}
workList[processPop[i]-1]+=1;
}
return checkResult;
}
private void GAMethod(){
//初始化
initPop();
// System.out.println("初始种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCode[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCode[i][j]+"\t");
// }
// System.out.println();
// }
//初始最优个体与适应值
initFitness();
System.out.println("最优个体:"+targetBest);
for(int i=0;i<processNum;i++){
System.out.print(processBest[i]+"\t");
}
System.out.println();
for(int i=0;i<processNum;i++){
System.out.print(deviceBest[i]+"\t");
}
//迭代记录
int iter=0;
while(iter<ITER){
// System.out.println();
// System.out.println("=========第"+(iter+1)+"次迭代=========");
// System.out.println("最优值:"+targetBest);
//扰动
int[][] processCodeTemp=processCode.clone();
int[][] deviceCodeTemp=deviceCode.clone();
for(int i=0;i<popNum;i++){
int[][] mutatePopTemp=mutationPop(processCode[i].clone(),deviceCode[i].clone(),true);
processCodeTemp[i]=mutatePopTemp[0].clone();
deviceCodeTemp[i]=mutatePopTemp[1].clone();
}
// System.out.println();
// System.out.println("扰动种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCodeTemp[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCodeTemp[i][j]+"\t");
// }
// System.out.println();
// }
//交叉
int[][] processCodeChild=processCode.clone();
int[][] deviceCodeChild=deviceCode.clone();
double[] selectedProb=rouletteStrategy(processCodeTemp,deviceCodeTemp);
int crossCount=0;
for(int i=0;i<processCode.length/2;i++){
int[] selectedIndex= selectPop(selectedProb);
int[][] crossResult=crossPop(selectedIndex);
processCodeChild[crossCount]=crossResult[0].clone();
deviceCodeChild[crossCount]=crossResult[2].clone();
crossCount++;
processCodeChild[crossCount]=crossResult[1].clone();
deviceCodeChild[crossCount]=crossResult[3].clone();
crossCount++;
}
// System.out.println();
// System.out.println("交叉种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCodeChild[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCodeChild[i][j]+"\t");
// }
// System.out.println();
// }
//变异
for(int i=0;i<popNum;i++){
int[][] mutatePopTemp=mutationPop(processCodeChild[i].clone(),deviceCodeChild[i].clone(),false);
processCodeChild[i]=mutatePopTemp[0].clone();
deviceCodeChild[i]=mutatePopTemp[1].clone();
}
// System.out.println();
// System.out.println("变异种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCodeChild[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCodeChild[i][j]+"\t");
// }
// System.out.println();
// }
//选择
generateChild(processCode.clone(),deviceCode.clone(),processCodeChild.clone(),deviceCodeChild.clone());
// System.out.println("子代种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCode[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCode[i][j]+"\t");
// }
// System.out.println();
// }
//更新
updateFitness();
iter++;
}
System.out.println("最优个体:"+targetBest);
for(int i=0;i<processNum;i++){
System.out.print(processBest[i]+"\t");
}
System.out.println();
for(int i=0;i<processNum;i++){
System.out.print(deviceBest[i]+"\t");
}
System.out.println();
greedyDecode(processBest,deviceBest,true);
}
}
完整代码(启发+遗传方法)
import ilog.concert.IloException;
import ilog.concert.IloNumVar;
import ilog.cplex.IloCplex;
import java.util.ArrayList;
import java.util.Random;
//启发方法求解,遗传算法求解,cplex求解
public class FlexibleShopSchedulingProblemDemo {
//实验数据
class Data{
//工件编号
int[] workId={1,2,3,4,5,6,7,8};
//工序
int[][] workProcess={
{1,2,3},
{1,2,3,4,5,6},
{1,2,3,4},
{1,2,3},
{1,2},
{1,2,3},
{1,2,3,4},
{1,2,3}
};
//工件交货期
double[] deliveryDate={60,100,120,80,60,80,Double.MAX_VALUE,100};
//设备编号
int[] deviceId={1,2,3,4,5,6,7,8};
//加工时间
double[][][] ProcessTime={
//工件1
{
{Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,12,Double.MAX_VALUE,10,9,Double.MAX_VALUE},
{17,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,17,10,Double.MAX_VALUE,15},
{Double.MAX_VALUE,24,Double.MAX_VALUE,11,Double.MAX_VALUE,Double.MAX_VALUE,10,Double.MAX_VALUE}
},
//工件2
{
{Double.MAX_VALUE,Double.MAX_VALUE,11,10,21,14,Double.MAX_VALUE,17},
{8,12,Double.MAX_VALUE,Double.MAX_VALUE,19,11,Double.MAX_VALUE,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,15,Double.MAX_VALUE,21,25,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,18,Double.MAX_VALUE,9,Double.MAX_VALUE,},
{12,15,Double.MAX_VALUE,14,9,Double.MAX_VALUE,10,Double.MAX_VALUE},
{Double.MAX_VALUE,9,Double.MAX_VALUE,7,10,8,Double.MAX_VALUE,Double.MAX_VALUE}
},
//工件3
{
{Double.MAX_VALUE,14,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,17,Double.MAX_VALUE},
{Double.MAX_VALUE,23,23,17,Double.MAX_VALUE,18,Double.MAX_VALUE,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,20,9,22,Double.MAX_VALUE,Double.MAX_VALUE,21},
{7,Double.MAX_VALUE,10,Double.MAX_VALUE,8,11,9,Double.MAX_VALUE}
},
//工件4
{
{Double.MAX_VALUE,18,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,17,18,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,10,Double.MAX_VALUE,Double.MAX_VALUE,12,Double.MAX_VALUE},
{Double.MAX_VALUE,8,11,8,Double.MAX_VALUE,Double.MAX_VALUE,9,20}
},
//工件5
{
{Double.MAX_VALUE,Double.MAX_VALUE,24,10,16,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,18,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,19}
},
//工件6
{
{Double.MAX_VALUE,20,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,22,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,18,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,19,Double.MAX_VALUE},
{19,Double.MAX_VALUE,17,16,16,Double.MAX_VALUE,Double.MAX_VALUE,18}
},
//工件7
{
{Double.MAX_VALUE,Double.MAX_VALUE,16,Double.MAX_VALUE,17,16,Double.MAX_VALUE,Double.MAX_VALUE},
{22,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,20,22,Double.MAX_VALUE,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,18,23,Double.MAX_VALUE,Double.MAX_VALUE},
{Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,10,Double.MAX_VALUE,24}
},
//工件8
{
{11,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,21,21},
{25,11,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE},
{24,18,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,25,Double.MAX_VALUE,20}
}
};
}
//作业结构类
class shopStructure implements Cloneable{
//工件编号
int workId;
//工序编号
int workProcess;
//设备编号
int deviceId;
//开始时间
double startTime;
//结束时间
double endTime;
//拷贝方法
@Override
public shopStructure clone() {
shopStructure shop = null;
try {
shop = (shopStructure) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return shop;
}
}
//定义类属性
//数据
Data data;
//工件
shopStructure shop;
//工序
ArrayList<ArrayList<Integer>>workProcess;
//调度结果
ArrayList<ArrayList<shopStructure>>workResult;
//记录工序的开始时间
double[][] startTime;
//记录工序的结束时间
double[][] endTime;
private FlexibleShopSchedulingProblemDemo(){
//初始化实验数据
data=new Data();
//初始化工件类
shop=new shopStructure();
//初始化工序
workProcess=new ArrayList<ArrayList<Integer>>();
for(int i=0;i<data.workProcess.length;i++){
ArrayList<Integer>workProcessTemp=new ArrayList<Integer>();
for(int j=0;j<data.workProcess[i].length;j++){
workProcessTemp.add(data.workProcess[i][j]);
}
workProcess.add(workProcessTemp);
}
//初始化调度结果
workResult=new ArrayList<ArrayList<shopStructure>>();
for(int i=0;i<data.deviceId.length;i++){
ArrayList<shopStructure> workResultTemp=new ArrayList<shopStructure>();
workResult.add(workResultTemp);
}
//初始化工序的开始时间和结束时间
startTime=new double[data.workProcess.length][6];
endTime=new double[data.workProcess.length][6];
for(int i=0;i<startTime.length;i++){
for(int j=0;j<6;j++){
startTime[i][j]=-1;
endTime[i][j]=-1;
}
}
}
/**
* 启发策略-最早开始时间
*/
private void EST(){
while (true) {
//遍历工件
for (int i = 0; i < data.workId.length; i++) {
//选取工序i的剩余第一个工序
if (workProcess.get(i).size() != 0) {
//System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
//随机生成设备遍历顺序
int[] orderArr = new int[data.deviceId.length];
for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
shuffle(orderArr);
//找到开始时间最短的机器设备
int deviceIndex = data.deviceId.length;
double deviceTime = Double.MAX_VALUE;
//随机遍历机器
for (int j = 0; j < data.deviceId.length; j++) {
//工序只能在可加工设备上进行加工
if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
if (workResult.get(orderArr[j]).size() == 0) {
//下一工序的开始时间大于等于上一工序的结束时间
if (workProcess.get(i).get(0) == 1) {
//第一个工序
deviceTime = 0;
deviceIndex = orderArr[j];
//System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
break;
}
} else {
if (workProcess.get(i).get(0) == 1) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
deviceIndex = orderArr[j];
}
} else {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
deviceIndex = orderArr[j];
}
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1;
deviceIndex = orderArr[j];
}
}
}
}
}
//System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
}
//更新工件信息
if (deviceIndex != data.deviceId.length) {
shop.workId = i + 1;
shop.workProcess = workProcess.get(i).get(0);
shop.deviceId = deviceIndex + 1;
shop.startTime = deviceTime;
startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
//System.out.println(i + "\t" + (workProcessTemp.get(i).get(0) - 1) + "\t" + deviceIndex);
shop.endTime = shop.startTime + data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];
endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
//工件信息加入结果列表
workResult.get(deviceIndex).add(shop.clone());
//删除该工序
workProcess.get(i).remove(0);
}
}
}
//所有工序分配完毕时,结束
boolean stopCondition = true;
for (int i = 0; i < data.workId.length; i++) {
if (workProcess.get(i).size() != 0) {
stopCondition = false;
break;
}
}
if (stopCondition) break;
}
printResult(workResult,endTime);
}
/**
* 启发策略-最早结束时间
* 随机分配工序
*/
private void EET(){
while (true) {
//遍历工件
for (int i = 0; i < data.workId.length; i++) {
//选取工序i的剩余第一个工序
if (workProcess.get(i).size() != 0) {
//System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
//随机生成设备遍历顺序
int[] orderArr = new int[data.deviceId.length];
for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
shuffle(orderArr);
//找到开始时间最短的机器设备
int deviceIndex = data.deviceId.length;
double deviceTime = Double.MAX_VALUE;
//随机遍历机器
for (int j = 0; j < data.deviceId.length; j++) {
//工序只能在可加工设备上进行加工
if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
if (workResult.get(orderArr[j]).size() == 0) {
//下一工序的开始时间大于等于上一工序的结束时间
if (workProcess.get(i).get(0) == 1) {
//第一个工序
deviceTime = data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
break;
}
} else {
if (workProcess.get(i).get(0) == 1) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]] < deviceTime) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
}
} else {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]]< deviceTime) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
}
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
}
}
}
}
}
//System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
}
//更新工件信息
if (deviceIndex != data.deviceId.length) {
shop.workId = i + 1;
shop.workProcess = workProcess.get(i).get(0);
shop.deviceId = deviceIndex + 1;
shop.endTime = deviceTime;
endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
shop.startTime = shop.endTime - data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];;
startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
//工件信息加入结果列表
workResult.get(deviceIndex).add(shop.clone());
//删除该工序
workProcess.get(i).remove(0);
}
}
}
//所有工序分配完毕时,结束
boolean stopCondition = true;
for (int i = 0; i < data.workId.length; i++) {
if (workProcess.get(i).size() != 0) {
stopCondition = false;
break;
}
}
if (stopCondition) break;
}
printResult(workResult,endTime);
}
/**
* 贪婪启发策略-最早开始时间
* 匈牙利算法分配第一工序和设备
*/
private void GEST(){
//第一个工序分配
int[] assignResult=shopAssign(data.ProcessTime);
//分配第一个工序
for(int i=0;i<assignResult.length;i++){
int deviceIndex = data.deviceId.length;
double deviceTime = Double.MAX_VALUE;
if (workProcess.get(i).size() != 0){
if (workResult.get(assignResult[i]-1).size() == 0){
deviceTime = 0;
deviceIndex = assignResult[i]-1;
}
else{
deviceTime = workResult.get(assignResult[i]-1).get(workResult.get(assignResult[i]-1).size() - 1).endTime+1;
deviceIndex = assignResult[i]-1;
}
}
if (deviceIndex != data.deviceId.length) {
shop.workId = i + 1;
shop.workProcess = workProcess.get(i).get(0);
shop.deviceId = deviceIndex + 1;
shop.startTime = deviceTime;
startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
shop.endTime = shop.startTime + data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];
endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
workResult.get(deviceIndex).add(shop.clone());
workProcess.get(i).remove(0);
}
}
//分配其余工序
while (true) {
//遍历工件
for (int i = 0; i < data.workId.length; i++) {
//选取工序i的剩余第一个工序
if (workProcess.get(i).size() != 0) {
//System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
//随机生成设备遍历顺序
int[] orderArr = new int[data.deviceId.length];
for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
shuffle(orderArr);
//找到开始时间最短的机器设备
int deviceIndex = data.deviceId.length;
double deviceTime = Double.MAX_VALUE;
//随机遍历机器
for (int j = 0; j < data.deviceId.length; j++) {
//工序只能在可加工设备上进行加工
if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
if (workResult.get(orderArr[j]).size() == 0) {
//下一工序的开始时间大于等于上一工序的结束时间
if (workProcess.get(i).get(0) == 1) {
//第一个工序
deviceTime = 0;
deviceIndex = orderArr[j];
//System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
break;
}
} else {
if (workProcess.get(i).get(0) == 1) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
deviceIndex = orderArr[j];
}
} else {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < deviceTime) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1;
deviceIndex = orderArr[j];
}
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1;
deviceIndex = orderArr[j];
}
}
}
}
}
//System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
}
//更新工件信息
if (deviceIndex != data.deviceId.length) {
shop.workId = i + 1;
shop.workProcess = workProcess.get(i).get(0);
shop.deviceId = deviceIndex + 1;
shop.startTime = deviceTime;
startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
//System.out.println(i + "\t" + (workProcessTemp.get(i).get(0) - 1) + "\t" + deviceIndex);
shop.endTime = shop.startTime + data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];
endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
//工件信息加入结果列表
workResult.get(deviceIndex).add(shop.clone());
//删除该工序
workProcess.get(i).remove(0);
}
}
}
//所有工序分配完毕时,结束
boolean stopCondition = true;
for (int i = 0; i < data.workId.length; i++) {
if (workProcess.get(i).size() != 0) {
stopCondition = false;
break;
}
}
if (stopCondition) break;
}
printResult(workResult,endTime);
}
/**
* 贪婪启发策略-最早结束时间
* 匈牙利算法分配第一工序和设备
*/
private void GEET(){
//第一个工序分配
int[] assignResult=shopAssign(data.ProcessTime);
//分配第一个工序
for(int i=0;i<assignResult.length;i++){
int deviceIndex = data.deviceId.length;
double deviceTime = Double.MAX_VALUE;
if (workProcess.get(i).size() != 0){
if (workResult.get(assignResult[i]-1).size() == 0){
deviceTime = data.ProcessTime[i][workProcess.get(i).get(0)-1][assignResult[i]-1];
deviceIndex = assignResult[i]-1;
}
else{
deviceTime = workResult.get(assignResult[i]-1).get(workResult.get(assignResult[i]-1).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][assignResult[i]-1];
deviceIndex = assignResult[i]-1;
}
}
if (deviceIndex != data.deviceId.length) {
shop.workId = i + 1;
shop.workProcess = workProcess.get(i).get(0);
shop.deviceId = deviceIndex + 1;
shop.endTime = deviceTime;
endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
shop.startTime = shop.endTime - data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];;
startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
workResult.get(deviceIndex).add(shop.clone());
workProcess.get(i).remove(0);
}
}
//分配其余工序
while (true) {
//遍历工件
for (int i = 0; i < data.workId.length; i++) {
//选取工序i的剩余第一个工序
if (workProcess.get(i).size() != 0) {
//System.out.println("=======工件"+(i+1)+"|工序"+workProcess.get(i).get(0)+"=======");
//随机生成设备遍历顺序
int[] orderArr = new int[data.deviceId.length];
for (int j = 0; j < data.deviceId.length; j++) orderArr[j] = j;
shuffle(orderArr);
//找到开始时间最短的机器设备
int deviceIndex = data.deviceId.length;
double deviceTime = Double.MAX_VALUE;
//随机遍历机器
for (int j = 0; j < data.deviceId.length; j++) {
//工序只能在可加工设备上进行加工
if (data.ProcessTime[i][workProcess.get(i).get(0) - 1][orderArr[j]] != Double.MAX_VALUE) {
if (workResult.get(orderArr[j]).size() == 0) {
//下一工序的开始时间大于等于上一工序的结束时间
if (workProcess.get(i).get(0) == 1) {
//第一个工序
deviceTime = data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
break;
}
} else {
if (workProcess.get(i).get(0) == 1) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]] < deviceTime) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
}
} else {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]]< deviceTime) {
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime >= endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
}
if (workResult.get(orderArr[j]).get(workResult.get(orderArr[j]).size() - 1).endTime < endTime[i][workProcess.get(i).get(0) - 2]) {
deviceTime = endTime[i][workProcess.get(i).get(0) - 2]+1+data.ProcessTime[i][workProcess.get(i).get(0)-1][orderArr[j]];
deviceIndex = orderArr[j];
}
}
}
}
}
//System.out.println("遍历设备"+(orderArr[j]+1)+"\t"+"目标设备"+(deviceIndex+1)+"\t"+deviceTime);
}
//更新工件信息
if (deviceIndex != data.deviceId.length) {
shop.workId = i + 1;
shop.workProcess = workProcess.get(i).get(0);
shop.deviceId = deviceIndex + 1;
shop.endTime = deviceTime;
endTime[i][workProcess.get(i).get(0) - 1] = shop.endTime;
shop.startTime = shop.endTime - data.ProcessTime[i][workProcess.get(i).get(0) - 1][deviceIndex];;
startTime[i][workProcess.get(i).get(0) - 1] = shop.startTime;
//工件信息加入结果列表
workResult.get(deviceIndex).add(shop.clone());
//删除该工序
workProcess.get(i).remove(0);
}
}
}
//所有工序分配完毕时,结束
boolean stopCondition = true;
for (int i = 0; i < data.workId.length; i++) {
if (workProcess.get(i).size() != 0) {
stopCondition = false;
break;
}
}
if (stopCondition) break;
}
printResult(workResult,endTime);
}
private int[] shopAssign(double[][][] ProcessTime){
int[] assignResult=new int[data.workId.length];
double[][] fistProcess=new double[data.workId.length][data.deviceId.length];
for(int i=0;i<data.workId.length;i++){
for(int j=0;j<data.deviceId.length;j++){
fistProcess[i][j]=ProcessTime[i][0][j];
}
}
//匈牙利算法分配第一工序
HungarianAlgorithm lp2=new HungarianAlgorithm(fistProcess);
lp2.hungarianMethod();
int N = lp2.m.length;
double finalAnswer = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (lp2.m[i][j] == -1) {
assignResult[i]=j+1;
}
}
}
// System.out.println("=================");
// for(int i=0;i<assignResult.length;i++){
// System.out.print(assignResult[i]+"\t");
// }
return assignResult;
}
//数组元素交换
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//数组随机打乱
private static void shuffle(int[] arr) {
Random rand = new Random();
for (int i = arr.length; i > 0; i--) {
int randInd = rand.nextInt(i);
swap(arr, randInd, i - 1);
}
}
//打印结果
private void printResult(ArrayList<ArrayList<shopStructure>>workResult,double[][] endTime){
for(int i=0;i<workResult.size();i++){
System.out.println("=======设备"+(i+1)+"=======");
for(int j=0;j<workResult.get(i).size();j++){
System.out.println("工件"+workResult.get(i).get(j).workId+"\t"+"工序"+workResult.get(i).get(j).workProcess);
System.out.println(workResult.get(i).get(j).startTime+"\t"+workResult.get(i).get(j).endTime+"\t"+data.ProcessTime[workResult.get(i).get(j).workId-1][workResult.get(i).get(j).workProcess-1][workResult.get(i).get(j).deviceId-1]);
}
}
double[] endTimeList=new double[data.workId.length];
for(int i=0;i<endTime.length;i++){
endTimeList[i]=getMax(endTime[i]);
System.out.println("工件"+(i+1)+"完工时间:"+endTimeList[i]);
}
System.out.println("最大完工时间:"+getMax(endTimeList));
}
//获取数组的最大值
private double getMax(double[] arr) {
double max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
//遗传算法求解
GAAlgorithm ga=new GAAlgorithm();
class GAAlgorithm{
Data data;
//工件
shopStructure shop;
//种群个数
int popNum;
//工序个数
int processNum;
//迭代次数
int ITER;
//工序列表
ArrayList<Integer>processList;
//工序编码
int[][] processCode;
//设备编码
int[][] deviceCode;
//工序可用设备编码
ArrayList<ArrayList<ArrayList<Integer>>> processDevice;
//最优工序个体
int[] processBest;
//最优设备个体
int[] deviceBest;
//最优目标值
double targetBest;
//调度结果
ArrayList<ArrayList<shopStructure>>workResult;
private GAAlgorithm(){
data=new Data();
//初始化工件类
shop=new shopStructure();
//种群个数
popNum=200;
processNum=0;
ITER=500;
for(int i=0;i<data.workProcess.length;i++){
processNum+=data.workProcess[i].length;
}
//工序编码
processCode=new int[popNum][processNum];
processList=new ArrayList<>();
for(int i=0;i<data.workProcess.length;i++){
for(int j=0;j<data.workProcess[i].length;j++){
processList.add(i+1);
}
}
//设备编码
deviceCode=new int[popNum][processNum];
//工序可用设备编码
processDevice=new ArrayList<>();
for(int i=0;i<data.ProcessTime.length;i++){
ArrayList<ArrayList<Integer>>processDevice1=new ArrayList<>();
for(int j=0;j<data.ProcessTime[i].length;j++){
double[] deviceTimeList=new double[data.deviceId.length];
int[] deviceTimeIndex=new int[data.deviceId.length];
for(int k=0;k<data.ProcessTime[i][j].length;k++){
deviceTimeList[k]=data.ProcessTime[i][j][k];
deviceTimeIndex[k]=k;
}
//由小到大排序
for(int ii=1;ii<deviceTimeList.length;ii++){
for(int jj=0;jj<deviceTimeList.length-ii;jj++){
if(deviceTimeList[jj]>deviceTimeList[jj+1]){
double temp=deviceTimeList[jj+1];
int tempIndex=deviceTimeIndex[jj+1];
deviceTimeList[jj+1]=deviceTimeList[jj];
deviceTimeIndex[jj+1]=deviceTimeIndex[jj];
deviceTimeList[jj]=temp;
deviceTimeIndex[jj]=tempIndex;
}
}
}
ArrayList<Integer>processDevice2=new ArrayList<>();
for(int k=0;k<data.ProcessTime[i][j].length;k++){
if(deviceTimeList[k]!=Double.MAX_VALUE){
processDevice2.add(deviceTimeIndex[k]+1);
}
}
processDevice1.add(processDevice2);
}
processDevice.add(processDevice1);
}
//最优工序个体
processBest=new int[processNum];
//最优设备个体
deviceBest=new int[processNum];
//最优目标值
targetBest=Double.MAX_VALUE;
//初始化调度结果
workResult=new ArrayList<ArrayList<shopStructure>>();
for(int i=0;i<data.deviceId.length;i++){
ArrayList<shopStructure> workResultTemp=new ArrayList<shopStructure>();
workResult.add(workResultTemp);
}
}
//种群初始化-个体编码
private void initPop(){
for(int i=0;i<popNum;i++){
int[] processRamdomIndex=processRandom();
for(int j=0;j<processNum;j++){
processCode[i][j]=processList.get(processRamdomIndex[j]-1);
}
int[] deviceRandomIndex=deviceRandom(processCode[i]);
for(int j=0;j<processNum;j++){
deviceCode[i][j]=deviceRandomIndex[j];
}
}
}
//初始最优个体与适应值
private void initFitness(){
for(int i=0;i<processCode.length;i++){
double temp=fitnessPop(processCode[i],deviceCode[i],false);
if(temp<targetBest){
targetBest=temp;
processBest=processCode[i].clone();
deviceBest=deviceCode[i].clone();
}
}
}
//个体变异:工序随机交换指定偶数位;设备随机选取
private int[][] mutationPop(int[] processPop,int[] devicePop,boolean mutateType){
int[][] newPop=new int[2][processPop.length];
newPop[0]=processPop.clone();
newPop[1]=devicePop.clone();
Random random = new Random();
int mutateNum;
int[] processIndex;
//交叉前变异
if(mutateType){
mutateNum=2;
processIndex=new int[mutateNum];
}
//交叉后变异
else{
//变异位数
mutateNum=processPop.length/5;
if(mutateNum%2!=0)mutateNum-=1;
processIndex=new int[mutateNum];
}
//工序变异位置
for(int i=0;i<processIndex.length;i++){
processIndex[i]=random.nextInt(newPop[0].length);
}
// System.out.println();
// System.out.println("工序变异位置");
// for(int i=0;i<processIndex.length;i++){
// System.out.print((processIndex[i]+1)+"\t");
// }
// System.out.println();
//工序变异
for(int i=0;i<processIndex.length;i+=2){
int temp=newPop[0][processIndex[i]];
newPop[0][processIndex[i]]=newPop[0][processIndex[i+1]];
newPop[0][processIndex[i+1]]=temp;
}
// System.out.println("工序变异结果");
// for(int j=0;j<newPop[0].length;j++){
// System.out.print(newPop[0][j]+"\t");
// }
// System.out.println();
//设备变异位置
for(int i=0;i<processIndex.length;i++){
//确定工序
int count=0;
for(int j=0;j<newPop[0].length;j++){
if(newPop[0][j]==newPop[0][processIndex[i]]){
newPop[1][j]=random.nextInt(processDevice.get(newPop[0][processIndex[i]]-1).get(count).size());
count+=1;
}
}
}
// System.out.println("设备变异结果");
// for(int i=0;i<newPop[1].length;i++){
// System.out.print(newPop[1][i]+"\t");
// }
return newPop;
}
//轮盘赌策略-计算选择概率
private double[] rouletteStrategy(int[][] processCodeChild,int[][] deviceCodeChild){
double[] selectedProb=new double[popNum];
double fitnessSum=0;
//计算个体适应值
for(int i=0;i<popNum;i++){
selectedProb[i]=fitnessPop(processCodeChild[i],deviceCodeChild[i],false);
fitnessSum+=selectedProb[i];
}
//反差
double selectedSum=0;
for(int i=0;i<popNum;i++){
selectedProb[i]=fitnessSum-selectedProb[i];
selectedSum+=selectedProb[i];
}
//计算累积概率
double[] selectedProbTemp=selectedProb.clone();
for(int i=0;i<popNum;i++){
if(i==0)selectedProb[i]=selectedProbTemp[i]/selectedSum;
else selectedProb[i]=(selectedProbTemp[i]/selectedSum)+selectedProb[i-1];
}
return selectedProb;
}
//个体选择
private int[] selectPop(double[] selectedProb){
int[] selectedIndex=new int[2];
Random random = new Random();
for(int i=0;i<selectedIndex.length;i++){
double temp=random.nextDouble(0,1);
//找到位置索引
for(int j=0;j<selectedProb.length;j++){
if(temp<=selectedProb[j]){
selectedIndex[i]=j;
break;
}
}
}
return selectedIndex;
}
//个体交叉
private int[][] crossPop(int[] selectedIndex){
int[][] crossResult=new int[4][processNum];
//随机交叉位置
int crossNum=processNum/5;
if(crossNum<=0)crossNum=1;
int[] crossIndex=new int[crossNum];
int[] arrTemp=new int[processNum];
for(int i=0;i<arrTemp.length;i++){
arrTemp[i]=i;
}
shuffle(arrTemp);
for(int i=0;i<crossIndex.length;i++){
crossIndex[i]=arrTemp[i];
}
// System.out.println("个体1交叉位置:");
// for(int i=0;i<crossIndex.length;i++){
// System.out.print(crossIndex[i]+"\t");
// }
// System.out.println();
//找到另一个体上的交叉位置
int[] anotherCrossIndex=new int[crossNum];
for(int i=0;i<anotherCrossIndex.length;i++){anotherCrossIndex[i]=-1;}
for(int i=0;i<crossIndex.length;i++){
for(int j=0;j<processCode[selectedIndex[1]].length;j++){
if(processCode[selectedIndex[1]][j]==processCode[selectedIndex[0]][crossIndex[i]]){
//是否已经添加过
boolean appendType=false;
for(int k=0;k<anotherCrossIndex.length;k++){
if(anotherCrossIndex[k]==j){
appendType=true;
break;
}
}
if(!appendType){
anotherCrossIndex[i]=j;
}
}
}
}
// System.out.println("个体2交叉位置:");
// for(int i=0;i<anotherCrossIndex.length;i++){
// System.out.print(anotherCrossIndex[i]+"\t");
// }
// System.out.println();
//交叉
for(int i=0;i<selectedIndex.length;i++){
int count=0;
for(int j=0;j<processNum;j++){
if(i==0){
if(judgeExist(crossIndex,j)){
crossResult[0][j]=processCode[selectedIndex[i]][j];
crossResult[2][j]=deviceCode[selectedIndex[i]][j];
}
else{
//另一个体当中选择第一个不在交叉位置的索引
while(true){
if(!judgeExist(anotherCrossIndex,count)){
break;
}
else{
count++;
}
}
crossResult[0][j]=processCode[selectedIndex[1-i]][count];
crossResult[2][j]=deviceCode[selectedIndex[1-i]][count];
count++;
}
}
else{
if(judgeExist(anotherCrossIndex,j)){
crossResult[1][j]=processCode[selectedIndex[i]][j];
crossResult[3][j]=deviceCode[selectedIndex[i]][j];
}
else{
//另一个体当中选择第一个不在交叉位置的索引
while(true){
if(!judgeExist(crossIndex,count)){
break;
}
else{
count++;
}
}
crossResult[1][j]=processCode[selectedIndex[1-i]][count];
crossResult[3][j]=deviceCode[selectedIndex[1-i]][count];
count++;
}
}
}
}
//校验设备分配-如果超出索引,则随机分配;
crossResult[2]=deviceCheck(crossResult[0].clone(),crossResult[2].clone());
crossResult[3]=deviceCheck(crossResult[1].clone(),crossResult[3].clone());
return crossResult;
}
//子代生成
private void generateChild(int[][] processCode,int[][] deviceCode,int[][] processCodeChild,int[][] deviceCodeChild){
//计算原种群适应值
double[] targetValue=new double[processCode.length+processCodeChild.length];
int[] targetIndex=new int[processCode.length+processCodeChild.length];
for(int i=0;i<processCode.length;i++){
targetValue[i]=fitnessPop(processCode[i].clone(),deviceCode[i].clone(),false);
targetIndex[i]=i;
}
for(int i=0;i<processCodeChild.length;i++){
targetValue[i+processCode.length]=fitnessPop(processCodeChild[i].clone(),deviceCodeChild[i].clone(),false);
targetIndex[i+processCode.length]=i+processCode.length;
}
//排序
for(int i=1;i<targetValue.length;i++){
for(int j=0;j<targetValue.length-i;j++){
if(targetValue[j]>targetValue[j+1]){
double temp=targetValue[j+1];
int tempIndex=targetIndex[j+1];
targetValue[j+1]=targetValue[j];
targetIndex[j+1]=targetIndex[j];
targetValue[j]=temp;
targetIndex[j]=tempIndex;
}
}
}
//生成子代
for(int i=0;i<this.processCode.length;i++){
if(targetIndex[i]<processCode.length){
this.processCode[i]=processCode[targetIndex[i]].clone();
this.deviceCode[i]=deviceCode[targetIndex[i]].clone();
}
else{
this.processCode[i]=processCodeChild[targetIndex[i]-processCode.length].clone();
this.deviceCode[i]=deviceCodeChild[targetIndex[i]-processCode.length].clone();
}
}
}
//更新最优个体与适应值
private void updateFitness(){
for(int i=0;i<processCode.length;i++){
double temp=fitnessPop(processCode[i],deviceCode[i],false);
if(temp<targetBest){
targetBest=temp;
processBest=processCode[i].clone();
deviceBest=deviceCode[i].clone();
}
}
}
//判断是否存在
private boolean judgeExist(int[] arr,int element){
boolean existType=false;
for(int i=0;i<arr.length;i++){
if(arr[i]==element){
existType=true;
break;
}
}
return existType;
}
//计算个体适应值
private double fitnessPop(int[] processPop,int[] devicePop,boolean rstType){
double fitness=0;
fitness=greedyDecode(processPop,devicePop,rstType);
return fitness;
}
//个体解码
private double greedyDecode(int[] processPop,int[] devicePop,boolean rstType){
//清空列表
workResult=new ArrayList<ArrayList<shopStructure>>();
for(int i=0;i<data.deviceId.length;i++){
ArrayList<shopStructure> workResultTemp=new ArrayList<shopStructure>();
workResult.add(workResultTemp);
}
// System.out.println("解码个体");
// for(int i=0;i<processPop.length;i++){
// System.out.print(processPop[i]+"\t");
// }
// System.out.println();
// for(int i=0;i<devicePop.length;i++){
// System.out.print(devicePop[i]+"\t");
// }
// System.out.println();
//记录开始和结束时间
double[][] startTime=new double[data.workId.length][6];
double[][] endTime=new double[data.workId.length][6];
for(int i=0;i<startTime.length;i++){
for(int j=0;j<6;j++){
startTime[i][j]=-1;
endTime[i][j]=-1;
}
}
//记录工件使用次数-工序
int[] workList=new int[data.workId.length];
//分配工序到设备
for(int i=0;i<processPop.length;i++){
// System.out.println("工序:");
// for(int ii=0;ii<workList.length;ii++){
// System.out.print(workList[ii]+"\t");
// }
// System.out.println();
int deviceIndex=processDevice.get(processPop[i]-1).get(workList[processPop[i]-1]).get(devicePop[i]);
double deviceTime = Double.MAX_VALUE;
if(workResult.get(deviceIndex-1).size()==0){
if(workList[processPop[i]-1]==0){
deviceTime=0;
}
else{
deviceTime = endTime[processPop[i]-1][workList[processPop[i]-1]-1]+1;
}
}
else{
//设备已存在分配的工序
//第一个工序分配
if(workList[processPop[i]-1]==0){
deviceTime=workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime+1;
}
else{
if (workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime >= endTime[processPop[i]-1][workList[processPop[i]-1]-1]) {
deviceTime = workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime+1;
}
if (workResult.get(deviceIndex-1).get(workResult.get(deviceIndex-1).size() - 1).endTime < endTime[processPop[i]-1][workList[processPop[i]-1]-1]) {
deviceTime = endTime[processPop[i]-1][workList[processPop[i]-1]-1]+1;
}
}
}
//更新工件信息
shop.workId = processPop[i];
shop.workProcess = workList[processPop[i]-1]+1;
shop.deviceId = deviceIndex;
shop.startTime = deviceTime;
startTime[processPop[i]-1][workList[processPop[i]-1]] = shop.startTime;
shop.endTime = shop.startTime + data.ProcessTime[processPop[i]-1][workList[processPop[i]-1]][deviceIndex-1];
endTime[processPop[i]-1][workList[processPop[i]-1]] = shop.endTime;
workResult.get(deviceIndex-1).add(shop.clone());
workList[processPop[i]-1]+=1;
}
//计算最大完工时间
double maxTime=maxEndTime(endTime);
if(rstType)printResult(workResult,endTime);
return maxTime;
}
//计算最大完工时间
private double maxEndTime(double[][] endTime){
double maxTime=0;
double[] endTimeList=new double[data.workId.length];
for(int i=0;i<endTime.length;i++){
endTimeList[i]=getMax(endTime[i]);
}
maxTime=getMax(endTimeList);
return maxTime;
}
//产生个体长度的随机数-工序
private int[] processRandom(){
int[] processSort=new int[processNum];
double[] processRandomValue=new double[processNum];
Random random = new Random();
for(int i=0;i<processNum;i++){
processRandomValue[i]=random.nextDouble(10);
processSort[i]=i+1;
}
//冒泡排序
for(int i=1;i<processRandomValue.length;i++){
for(int j=0;j<processRandomValue.length-i;j++){
if(processRandomValue[j]>processRandomValue[j+1]){
double temp=processRandomValue[j+1];
int tempIndex=processSort[j+1];
processRandomValue[j+1]=processRandomValue[j];
processSort[j+1]=processSort[j];
processRandomValue[j]=temp;
processSort[j]=tempIndex;
}
}
}
return processSort;
}
//产生个体长度的随机数-设备索引
private int[] deviceRandom(int[] processIndex){
int[] deviceRandomValue=new int[processNum];
int[] workList=new int[data.workId.length];
Random random = new Random();
int count=0;
for(int i=0;i<processNum;i++){
deviceRandomValue[count++]=random.nextInt(processDevice.get(processIndex[i]-1).get(workList[processIndex[i]-1]).size());
workList[processIndex[i]-1]+=1;
}
return deviceRandomValue;
}
//设备校验
private int[] deviceCheck(int[] processPop,int[] devicePop){
int[] checkResult=new int[devicePop.length];
int[] workList=new int[data.workId.length];
Random random = new Random();
for(int i=0;i<devicePop.length;i++){
int deviceIndexLength=processDevice.get(processPop[i]-1).get(workList[processPop[i]-1]).size();
if(devicePop[i]<deviceIndexLength){
checkResult[i]=devicePop[i];
}
else{
checkResult[i]=random.nextInt(deviceIndexLength);
}
workList[processPop[i]-1]+=1;
}
return checkResult;
}
private void GAMethod(){
//初始化
initPop();
// System.out.println("初始种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCode[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCode[i][j]+"\t");
// }
// System.out.println();
// }
//初始最优个体与适应值
initFitness();
System.out.println("最优个体:"+targetBest);
for(int i=0;i<processNum;i++){
System.out.print(processBest[i]+"\t");
}
System.out.println();
for(int i=0;i<processNum;i++){
System.out.print(deviceBest[i]+"\t");
}
//迭代记录
int iter=0;
while(iter<ITER){
// System.out.println();
// System.out.println("=========第"+(iter+1)+"次迭代=========");
// System.out.println("最优值:"+targetBest);
//扰动
int[][] processCodeTemp=processCode.clone();
int[][] deviceCodeTemp=deviceCode.clone();
for(int i=0;i<popNum;i++){
int[][] mutatePopTemp=mutationPop(processCode[i].clone(),deviceCode[i].clone(),true);
processCodeTemp[i]=mutatePopTemp[0].clone();
deviceCodeTemp[i]=mutatePopTemp[1].clone();
}
// System.out.println();
// System.out.println("扰动种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCodeTemp[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCodeTemp[i][j]+"\t");
// }
// System.out.println();
// }
//交叉
int[][] processCodeChild=processCode.clone();
int[][] deviceCodeChild=deviceCode.clone();
double[] selectedProb=rouletteStrategy(processCodeTemp,deviceCodeTemp);
int crossCount=0;
for(int i=0;i<processCode.length/2;i++){
int[] selectedIndex= selectPop(selectedProb);
int[][] crossResult=crossPop(selectedIndex);
processCodeChild[crossCount]=crossResult[0].clone();
deviceCodeChild[crossCount]=crossResult[2].clone();
crossCount++;
processCodeChild[crossCount]=crossResult[1].clone();
deviceCodeChild[crossCount]=crossResult[3].clone();
crossCount++;
}
// System.out.println();
// System.out.println("交叉种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCodeChild[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCodeChild[i][j]+"\t");
// }
// System.out.println();
// }
//变异
for(int i=0;i<popNum;i++){
int[][] mutatePopTemp=mutationPop(processCodeChild[i].clone(),deviceCodeChild[i].clone(),false);
processCodeChild[i]=mutatePopTemp[0].clone();
deviceCodeChild[i]=mutatePopTemp[1].clone();
}
// System.out.println();
// System.out.println("变异种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCodeChild[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCodeChild[i][j]+"\t");
// }
// System.out.println();
// }
//选择
generateChild(processCode.clone(),deviceCode.clone(),processCodeChild.clone(),deviceCodeChild.clone());
// System.out.println("子代种群:");
// for(int i=0;i<popNum;i++){
// System.out.println("个体"+(i+1)+"工序编码");
// for(int j=0;j<processNum;j++){
// System.out.print(processCode[i][j]+"\t");
// }
// System.out.println();
// System.out.println("个体"+(i+1)+"设备编码索引");
// for(int j=0;j<processNum;j++){
// System.out.print(deviceCode[i][j]+"\t");
// }
// System.out.println();
// }
//更新
updateFitness();
iter++;
}
System.out.println("最优个体:"+targetBest);
for(int i=0;i<processNum;i++){
System.out.print(processBest[i]+"\t");
}
System.out.println();
for(int i=0;i<processNum;i++){
System.out.print(deviceBest[i]+"\t");
}
System.out.println();
greedyDecode(processBest,deviceBest,true);
}
}
public static void main(String[] args){
FlexibleShopSchedulingProblemDemo lp=new FlexibleShopSchedulingProblemDemo();
lp.ga.GAMethod();
//lp.EST();
//lp.GEST();
//lp.EET();
//lp.GEET();
}
}
import java.util.Arrays;
public class HungarianAlgorithm{
double[][] a;
double m[][];
public HungarianAlgorithm(double[][] a){
this.a=new double[a.length][a[0].length];
for(int i=0;i<a.length;i++){
for(int j=0;j<a[i].length;j++){
this.a[i][j]=a[i][j];
}
}
}
public static void main(String[] args) {
double[][] a = { { 12, 7, 9, 7, 9 }, { 8, 9, 6, 6, 6 }, { 7, 17, 12, 14, 9 }, { 15, 14, 6, 6, 10 },
{ 4, 10, 7, 10, 9 } };
HungarianAlgorithm lp=new HungarianAlgorithm(a);
lp.hungarianMethod();
}
public void hungarianMethod(){
int L = a.length;
int S = a[1].length;
if (L <= S) {
double[][] b = new double[S - L][S];
for (int i = 0; i < S - L; i++) {
for (int j = 0; j < S; j++) {
b[i][j] = 0;
}
}
m = Arrays.copyOf(a, a.length + b.length);
System.arraycopy(b, 0, m, a.length, b.length);
int N = m.length;
double[][] c = new double[N][N];
c = copy(m, c);
guiyue(m);
tryAppoint(m);
double finalAnswer = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (m[i][j] == -1) {
finalAnswer += c[i][j];
}
}
}
}
}
public static void guiyue(double[][] m) {
int N = m.length;
for (int i = 0; i < N; i++) {
double min = Double.MAX_VALUE;
for (int j = 0; j < N; j++) {
if (m[i][j] < min) {
min = m[i][j];
}
}
for (int j = 0; j < N; j++) {
m[i][j] -= min;
}
}
for (int j = 0; j < N; j++) {
double min = Double.MAX_VALUE;
for (int i = 0; i < N; i++) {
if (m[i][j] < min) {
min = m[i][j];
}
}
for (int i = 0; i < N; i++) {
m[i][j] -= min;
}
}
}
public static void tryAppoint(double[][] m) {
int N = m.length;
int zeroNumber = 0;
int zeroNumber1 = -1;
while (zeroNumber1 != zeroNumber) {
zeroNumber1 = zeroNumber;
rowsAppoint(m);
colsAppoint(m);
zeroNumber = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (m[i][j] == 0) {
zeroNumber += 1;
}
}
}
}
do {
rowsAppoint2(m);
} while (rowsAppoint2(m));
if (judge(m)) {
printResult(m);
} else {
drawZeroLine(m);
}
}
public static void drawZeroLine(double[][] m) {
int N = m.length;
boolean[] rowIsChecked = new boolean[N];
boolean[] colIsChecked = new boolean[N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (m[i][j] == -1) {
rowIsChecked[i] = false;
break;
} else {
rowIsChecked[i] = true;
}
}
}
for (int j = 0; j < N; j++) {
colIsChecked[j] = false;
}
int trueCount = 0;
int trueCount1 = -1;
while (trueCount1 != trueCount) {
trueCount1 = trueCount;
for (int i = 0; i < N; i++) {
if (rowIsChecked[i]) {
for (int j = 0; j < N; j++) {
if (m[i][j] == -2) {
colIsChecked[j] = true;
}
}
}
}
for (int j = 0; j < N; j++) {
if (colIsChecked[j]) {
for (int i = 0; i < N; i++) {
if (m[i][j] == -1) {
rowIsChecked[i] = true;
}
}
}
}
trueCount = 0;
for (int i = 0; i < N; i++) {
if (rowIsChecked[i] == true) {
trueCount += 1;
}
}
for (int j = 0; j < N; j++) {
if (colIsChecked[j] == true) {
trueCount += 1;
}
}
}
int lineCount = 0;
for (int i = 0; i < N; i++) {
if (rowIsChecked[i] == false) {
lineCount += 1;
}
}
for (int j = 0; j < N; j++) {
if (colIsChecked[j] == true) {
lineCount += 1;
}
}
if (lineCount < N) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (m[i][j] < 0) {
m[i][j] = 0;
}
}
}
double minValue = Double.MAX_VALUE;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (rowIsChecked[i] == true && colIsChecked[j] == false) {
if (m[i][j] < minValue) {
minValue = m[i][j];
}
}
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (rowIsChecked[i] == true) {
m[i][j] -= minValue;
}
if (colIsChecked[j] == true) {
m[i][j] += minValue;
}
}
}
tryAppoint(m);
} else if (lineCount == N) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (m[i][j] < 0) {
m[i][j] = 0;
}
}
}
tryAppoint(m);
}
}
public static void rowsAppoint(double[][] m) {
int N = m.length;
for (int i = 0; i < N; i++) {
int rowCount = 0;
int colIndex = Integer.MIN_VALUE;
for (int j = 0; j < N; j++) {
if (m[i][j] == 0) {
rowCount += 1;
colIndex = j;
}
}
if (rowCount == 1) {
m[i][colIndex] = -1;
for (int i1 = 0; i1 < N; i1++) {
if (i1 == i) {
continue;
} else if (m[i1][colIndex] == 0) {
m[i1][colIndex] = -2;
}
}
}
}
}
public static boolean rowsAppoint2(double[][] m) {
boolean zeroExist = false;
int N = m.length;
int rowZeroNumber = Integer.MAX_VALUE;
for (int i = 0; i < N; i++) {
int rowZeroCount = 0;
for (int j = 0; j < N; j++) {
if (m[i][j] == 0) {
rowZeroCount += 1;
zeroExist = true;
}
}
if (rowZeroCount < rowZeroNumber && rowZeroCount != 0) {
rowZeroNumber = rowZeroCount;
}
}
for (int i = 0; i < N; i++) {
int rowCount = 0;
int colIndex = Integer.MAX_VALUE;
for (int j = 0; j < N; j++) {
if (m[i][j] == 0) {
rowCount += 1;
colIndex = j;
zeroExist = true;
}
}
if (rowCount == rowZeroNumber) {
if (Math.random() > 0.95) {
for (int i1 = 0; i1 < N; i1++) {
if (m[i1][colIndex] == 0) {
m[i1][colIndex] = -2;
}
}
for (int j1 = 0; j1 < N; j1++) {
if (m[i][j1] == 0) {
m[i][j1] = -2;
}
}
m[i][colIndex] = -1;
break;
}
}
}
return zeroExist;
}
public static void colsAppoint(double[][] m) {
int N = m.length;
for (int j = 0; j < N; j++) {
int colCount = 0;
int rowIndex = Integer.MIN_VALUE;
for (int i = 0; i < N; i++) {
if (m[i][j] == 0) {
colCount += 1;
rowIndex = i;
}
}
if (colCount == 1) {
m[rowIndex][j] = -1;
for (int j1 = 0; j1 < N; j1++) {
if (j1 == j) {
continue;
} else if (m[rowIndex][j1] == 0) {
m[rowIndex][j1] = -2;
}
}
}
}
}
public static boolean judge(double[][] m) {
int count = 0;
int N = m.length;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (m[i][j] == -1) {
count += 1;
}
}
}
return count == N;
}
public static double[][] copy(double[][] m, double[][] a) {
int N = m.length;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
a[i][j] = m[i][j];
}
}
return (a);
}
public static void printM(double[][] m) {
int N = m.length;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(m[i][j] + " ");
}
System.out.println();
}
}
public static void printResult(double[][] m) {
int N = m.length;
double finalAnswer = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (m[i][j] == -1) {
System.out.print((i + 1) + "--" + (j + 1) + " ");
}
}
}
}
}
========================================
今天到此为止,后续记录其他应用问题的学习过程。
以上学习笔记,如有侵犯,请立即联系并删除!