关于蚁群算法:
蚁群系统(Ant System或Ant Colony System)是由意大利学者Dorigo、Maniezzo等人于20世纪90年代首先提出来的。他们在研究蚂蚁觅食的过程中,发现单个蚂蚁的行为比较简单,但是蚁群整体却可以体现一些智能的行为。例如蚁群可以在不同的环境下,寻找最短到达食物源的路径。这是因为蚁群内的蚂蚁可以通过某种信息机制实现信息的传递。后又经进一步研究发现,蚂蚁会在其经过的路径上释放一种可以称之为“信息素”的物质,蚁群内的蚂蚁对“信息素”具有感知能力,它们会沿着“信息素”浓度较高路径行走,而每只路过的蚂蚁都会在路上留下“信息素”,这就形成一种类似正反馈的机制,这样经过一段时间后,整个蚁群就会沿着最短路径到达食物源了。
图的生成:
车间调度问题我们可以转换为近似于最大流问题。任务当中的每一个阶段,都是这个图当中的一个节点。我们新增一个超级源点,超级源点和所有任务的第一阶段相连。其他的节点,当同时满足属于同一任务的两个节点中间不跳跃阶段的条件下相连。
图的遍历:
初始情况下,将蚂蚁统一放置到超级源点,并且将整个图的所有路径上的信息素设为一个固定值。之后,所有蚂蚁一起向终点行动,蚂蚁会受到信息素的影响,蚂蚁选择路径的方式是蚂蚁当前可走路径的信息素加和,作为取随机数m的最大值,通过随机数m和可选信息素,计算出蚂蚁选择的路径。当所有蚂蚁都走到终点的时候,将全图的信息素按照信息素消散参数进行消散,并计算出这些蚂蚁的路径。这个路径一种工件加工的顺序,按照这个顺序计算出工件加工的时间T。通过这个时间,计算出这个蚂蚁新增的信息素W=Q/T(Q是一个常数)。这个蚂蚁之前经历过的路径上的信息素都加上W。当所有的蚂蚁的信息素全部新增到图当中的时候。将所有蚂蚁再放回到起点,重复之前的步骤,随着重复次数的增多,蚂蚁会越来越向着最优解靠近。
最优解的寻找:
在计算蚂蚁行走的路径过程中,会时刻记录着当前出现过的,工件加工时间最短的情况。在程序结束之后,把最短的加工时间输出出来。
#include<bits/stdc++.h>
#define MAXN 60 //最大工作量
#define INIT_PRE 3000//道路初始信息素量
#define K 2000 //循环次数
#define DIS 0.5 //信息素消散速率
#define SUPER_START 48
using namespace std;
int totalStep;
int Step[MAXN];
int phe[MAXN][MAXN][MAXN][MAXN];
int n,m;
struct Pair
{
int i,j;
void get(int a,int b)
{
i=a;j=b;
}
}Jobnum[MAXN];
struct Job
{
int machine;
int len;
}job[MAXN][MAXN];
struct Ant
{
int JobStep[MAXN]; //任务已运行步数
int path[MAXN];
int pathlen;
int getFullPath()
{
int sum=0;
for (int i=0;i<pathlen;i++)
sum+=path[i];
return sum;
}
Pair paths[MAXN];
};
void init()
{
//totalStep=0;
memset(phe,0,sizeof(phe));
for (int i=0;i<totalStep;i++)
for (int j=0;j<totalStep;j++)
for (int k=0;k<totalStep;k++)
for (int l=0;l<totalStep;l++)
phe[i][j][k][l]=INIT_PRE;
for (int i=0;i<totalStep;i++)
for (int j=0;j<totalStep;j++)
phe[SUPER_START][SUPER_START][i][j]=INIT_PRE;
return;
}
void Dissipation()
{
for (int i=0;i<totalStep;i++)
for (int j=0;j<totalStep;j++)
for (int k=0;k<totalStep;k++)
for (int l=0;l<totalStep;l++)
phe[i][j][k][l] *= DIS;
for (int i=0;i<totalStep;i++)
for (int j=0;j<totalStep;j++)
phe[SUPER_START][SUPER_START][i][j]*= DIS;
return;
}
struct Recording
{
int start;
int ed;
int job;
int machine;
};
int timeCalcu(int Job[], bool draw)
{
int sum=0;
int machineWorkTime[MAXN];
int JobLast[MAXN];
int JobStep[MAXN];
Recording rec[MAXN];
memset(machineWorkTime,0,sizeof(machineWorkTime));
memset(JobLast,0,sizeof(JobLast));
memset(JobStep,0,sizeof(JobStep));
memset(rec,0,sizeof(rec));
for (int k = 0; k < totalStep; k++)
{
int i = Job[k];
rec[k].start = max(JobLast[i],machineWorkTime[job[i][JobStep[i]].machine]);
rec[k].job = i;
rec[k].ed = rec[k].start + job[i][JobStep[i]].len;
JobLast[i] = rec[k].ed;
rec[k].machine = job[i][JobStep[i]].machine;
machineWorkTime[job[i][JobStep[i]].machine] = rec[k].ed;
JobStep[i]++;
}
for (int i = 0; i < m; i++)
{
sum = max(sum,machineWorkTime[i]);
}
if (draw == true)
{
int gantt[MAXN][MAXN];
memset(gantt,0,sizeof(gantt));
for (int i=0;i<totalStep;i++)
{
for (int j=rec[i].start;j<rec[i].ed;j++)
{
gantt[rec[i].machine][j]=rec[i].job+1;
}
}
for (int i=0;i<m;i++)
for (int j=0;j<sum;j++)
printf("%d%c",gantt[i][j],j==sum-1?'\n':' ');
}
return sum;
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
totalStep = 0;
for (int i=0;i<n;i++)
{
scanf("%d",&Step[i]);
totalStep+=Step[i];
for (int j=0;j<Step[i];j++)
{
scanf("%d%d",&job[i][j].machine,&job[i][j].len);
}
}
init();
int antnum=totalStep*2;
Ant ant[antnum+5];
Ant bestAnt;
int bstime = 999999;
for (int sl=0;sl<10;sl++)
{
//printf("%d/10\n",sl);
srand(time(0));
memset(ant,0,sizeof(ant));
for (int i=0;i<antnum;i++)//第i只蚂蚁的旅程
{
//printf("sl=%d/%d\n",i,antnum);
int nowJob=SUPER_START; //作为图的超级源点
ant[i].JobStep[nowJob]=SUPER_START;
for (int j=0;j<totalStep;j++)
{
int allpre=0;
for (int k=0;k<m;k++)
{
//printf("i:%d j:%d k:%d l:%d ant:%d\n",nowJob,ant[i].JobStep[nowJob],k,ant[i].JobStep[k],i);
if (ant[i].JobStep[k]==Step[k]) continue;
allpre += phe[nowJob][ ant[i].JobStep[nowJob] ][k][ ant[i].JobStep[k] ];
}
//printf("%d\n",allpre);
int randSelectNum = rand()*rand() % allpre;//printf("OK\n");
//printf("摇到的数字是:%d\n",randSelectNum);
int select=0;
while (randSelectNum>=0)
{
if (ant[i].JobStep[select]==Step[select]) {select++;continue;}
randSelectNum -= phe[nowJob][ ant[i].JobStep[nowJob] ][select][ ant[i].JobStep[select] ];
select++;
}
select--;
//printf("蚂蚁选择了%d\n",select);
//蚂蚁选中的任务
ant[i].path[ant[i].pathlen]=select;
ant[i].paths[ant[i].pathlen++].get(select,ant[i].JobStep[select]);
ant[i].JobStep[select]++;
nowJob = select;
//printf("选择任务%d 阶段%d\n",select,ant[i].JobStep[select]);
}
}
Dissipation(); //每次蚂蚁行走完后,信息素都会消散
for (int i = 0; i < antnum; i++)
{
int ans = timeCalcu(ant[i].path,false);
if (ans<bstime && totalStep<=ans)
{
bstime = ans;
bestAnt = ant[i];
}
int reward = 2000/ans; //答案越小,奖励越多。
for (int j=0;j<ant[i].pathlen-1;j++)
{
int a = ant[i].paths[j].i;
int b = ant[i].paths[j].j;
int c = ant[i].paths[j+1].i;
int d = ant[i].paths[j+1].j;
phe[a][b][c][d] += reward;
}
}
//if (sl==1999)
/*for (int i = 0; i < antnum; i++)
{
for (int j=0; j<ant[i].pathlen; j++)
{
printf("%d%c",ant[i].path[j]+1,j==ant[i].pathlen-1?'\n':' ');
}
printf("\n%d\n",timeCalcu(ant[i].path,true));
}*/
}
printf("bestTime:%d\n",bstime);
printf("甘特图:\n");
timeCalcu(bestAnt.path,true);
printf("加工顺序为:");
for (int i=0;i<totalStep;i++)
printf("%d%s",bestAnt.path[i]+1,i==totalStep-1?"\n":"->");
/*int a[10] = {1,2,1,0,2,1,0,0};
timeCalcu(a,true);*/
return 0;
}
}
运行结果: