蚁群算法解决车间调度问题

关于蚁群算法:

蚁群系统(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;
    }
}

运行结果:
在这里插入图片描述

  • 13
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值