模拟退火算法解决工作指派问题(c++代码实现)

最近学习到模拟退火算法,遇到工作指派问题,但是查到网上的c++代码并不能解决问题,于是在它的基础上进行修改,完美解决了4工作4工人工作指派问题。

一、问题概述与分析

1.工作指派问题

n个工作可以由n个工人分别完成。工人i完成工作j的时间为dij ,问如何安排可使总的工作时间达到最小。试按SA思想设计一个该问题的求解算法,并利用计算机语言实现设计的算法。

2.分析:

1)假设有四个工人,四个工作,每个工人完成每项工作的时间如下表所示:

1

2

3

扫描二维码关注公众号,回复: 3714467 查看本文章

4

1

10

9

8

7

2

3

4

5

6

3

2

1

1

2

4

4

3

5

6

于是工人的工作时间构成了一个4×4的矩阵D[i][j],称为工作时间矩阵。

(2)这四个工作由四个工人分别完成,意思是每个工人只能做其中一个工作,一个工作只需由一个工人完成。例如1->3->2->4表示第1324个工人分别完成第i个工作(i=1,2,3,4)。

(3)p[i]存放工人序号,工作顺序保持1234不变。这样求解总工作时间最=最优解时,只需要交换工人序号,D[p[i]][j]表示工人p[i]做工作j的时间。

则该问题的数学形式表示为:

minimize的最优p[i]顺序

二、算法设计

编码方式:顺序编码

初始解:随机产生

邻域移动方式:2-opt,即两两交换

初始温度:T0=2000

终止温度:Tf=0

降温函数:Tk+1=Tkrr=0.95

内循环次数:In_loop=13000

外循环次数:Out_loop=20000

三、算法流程

Step1:选定一个初始解1->2->3->4,初始温度:T0=2000,终止温度:Tf=0,令迭代指标k=0Tk=T0

Step2:随机产生邻域解,计算目标值增量

Step3(内循环流程):设置内循环停止条件,只要达不到内循环停止条件,则进行如下判断:

,令cur=new;

否则产生

,令cur=new;

,令cur=cur

Step4:若达到内循环停止准则,跳转step5;否则跳转step2

Step5:令k=k+1,更新Tk,然后是否满足外循环停止准则,若满足则停止,否则跳转step2

四、算法程序实现

该算法的程序实现可以用c++c#python等多种语言,本文采用c++进行编程。

/***********************************************************************  模拟退火算法解决工作指派问题
***********************************************************************/
#include <iostream>
#include <cmath>
#include <time.h>
#include <stdio.h>
using namespace std;
const int MAXN = 50;           //最大约束数n
const double INIT_T =2000;      //初始温度
const double RATE = 0.95;        //温度衰减率
const double FINAL_T = 0;    //终止温度
const int IN_LOOP = 13000;      //内层循环次数
const int OUT_LOOP = 20000;       //外层循环次数
struct work {                   //定义工作结构类型
     int p[MAXN];             //工人序号
     double time;              //时间
 };
int N=4;                          //工人数量
double D[MAXN][MAXN];        //工作时间
int x[MAXN][ MAXN];           //选择工人与工作
work bestwork;                   //最优的遍历路径


void swap(int &a,int &b)         //注意&a和&b 我们要的p[]里存储的数据
  {
 int t;
      t=a;a=b;b=t;
  }
inline double totaldist(work q)        //计算总时间
 {
    int a,b,c,d;
    double cost = 0;
    a=q.p[0];
    b=q.p[1];
    c=q.p[2];
    d=q.p[3];
    cost=D[a][0]+D[b][1]+D[c][2]+D[d][3];
    return cost;
 }
void init()                     //读入数据,并初始化//输入时间矩阵D[i][j] 格式:工人i 工作j
{
   int i=0,j=0;
for(i=0;i<N;i++)
{
  for(j=0;j< N;j++)


  cin>> D[i][j];


}


for (i=0; i<N; i++)    //最优解的初始状态
    {
         bestwork.p[i] = i;


     }
     bestwork.time = totaldist(bestwork);
}
/***********************************************************************               产生指派方法
***********************************************************************/
work getnext(work p)   //新解产生函数
 {
     int x, y;
     work ret;
     ret = p;
     do {
         x = rand() % 4;
         y = rand() % 4 ;//x,y产生0-3的随机数
        }while(x == y);
     swap(ret.p[x], ret.p[y]);     //交换两工人位置顺序
     ret.time = totaldist(ret);
     return ret;
 }
/***********************************************************************                     退火和降温过程
 **********************************************************************/
  work sa()
 {
    double T;               //温度
    work curwork,newwork; //当前指派和新指派
    int i,A_t=0;
    double delta;
    T = INIT_T;     //赋值初始温度
    curwork = bestwork;
    while(true)                            //内循环
     {
        for (i=1; i<=IN_LOOP; i++)
        {
            newwork = getnext(curwork);    //获取新路径
            delta = newwork.time - curwork.time;
            if (delta < 0.0)
            {
                curwork = newwork;
            }
            else
             {
                double rnd = rand()%1001/1000;     //随机产生0-1的浮点数
                double p = exp(-delta/T);
                if (p > rnd)
                    curwork = newwork;
                else
                    curwork=curwork;
              }
            A_t++;
          }
          T = T * RATE;    //降温
if ( A_t >= OUT_LOOP || T < FINAL_T) break;       //外循环停止条件


      }
      return newwork;
}
/***********************************************************************                  程序主函数
  *********************************************************************/
int main()
 {
    init();
    printf("初始工作指派: %.4f\n", bestwork.time);
for(int i=0;i<N;i++)
{
printf(" %d->", bestwork.p[i]+1);
}
  printf("\n");
    bestwork=sa();
    printf("最优工作指派: %.4f\n", bestwork.time);
for(int j=0;j<N;j++)
{
printf(" %d->",bestwork.p[j]+1);
}
printf("\n");
    system("pause");
    return 0;
}

五、结果展示

最优指派方法:工人1234分别做工作4213

这样的到最小总工作时间为18小时。


猜你喜欢

转载自blog.csdn.net/qq_33251995/article/details/78159128