蚁群算法解决车间调度问题
關于蟻群算法:
蟻群系統(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;} }運行結果:
總結
以上是生活随笔為你收集整理的蚁群算法解决车间调度问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 职工线上健步走活动小程序方案,通过微信小
- 下一篇: 青龙面板+Ninja的企业微信通知设置以