模拟退火解决单机调度问题

模拟退火解单机调度问题

1.模拟退火简介

请参考:https://www.cnblogs.com/GuoJiaSheng/p/4192301.html

百度百科:模拟退火

模拟退火还是比较好理解的。

2.单机调度问题简介

已知:有n个工件{ J1,J2, …, Jn }需要在一台机器M0上加工。工件i会在时刻ai到达机器处,并期望在时刻di前完成加工,另已知该工件的加工时长pi。

工件上的约束:每个工件上只可被机器加工一次,且只有在工件到达机器处后才可以被加工。

机器上的约束:每个机器某一个时刻最多只能执行一个工件,而且执行过程是非抢占的。

目标:给出调度方案,使调度总延迟时间最小。

总结:就是说一台机器加工一堆零件,每个零件加工一次,然后每个工件有到达时间,加工时间和期望完成时间,合理安排工件加工顺序使得最终的延迟时间之和最小。

测试用例:

这里写图片描述

转化为输入如下:

8
0 15 21
0 19 25
0 26 30
0 9 13
15 13 28
15 15 40
24 12 65
34 6 75

3.测试代码如下:

代码注释说明的很清楚了…

/**
 * date: 2018-06-10
 * author: silvester
 * (utf-8) 编译环境:gcc version 5.3.0 (GCC) -std=c++11
 */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>

#define INF 0x3f3f3f3f
#define T 2000//初始温度
#define MIN_T 1e-8//最低温度
#define DELATE 0.98//温度降低速率
#define ILOOP 100//每个温度下搜索后继节点的个数

struct Path{//一种调度方案
    int obj[100];//这种调度方案给出的工件加工排列
    int delay;//这种调度方案延时
};
struct Path bestpath;//最优调度方案

typedef struct object{//对工件定义一个结构体
    int a,p,d;//三个变量分别是到达时间,加工时间,期望完成时间
}Obj;
Obj J[100];//工件集合

int n;//工件数量

void printPath(Path path)//输出一种调度方案的结果
{
    int i;
    for(i=0;i<n;i++){//输出依次加工的工件信息
        printf("No.%d : %d %d %d\n",i+1,J[path.obj[i]].a,J[path.obj[i]].p,J[path.obj[i]].d);
    }
    printf("delay:%d\n",path.delay);//输出延时
}

void Init()//初始化,给出一种排列
{
    int now=0;
    bestpath.delay=0;
    for(int i=0;i<n;i++)
    {
        //按输入工件的顺序做初始化排列顺序
        bestpath.obj[i]=i;

        //对这种排列进行延时计算
        if(now<J[i].a) now=J[i].a;
        now+=J[i].p;
        if(now>J[i].d) bestpath.delay+=(now-J[i].d);
    }
}

/*获取某一策略的后继节点*/
Path getNext(Path path)
{
    Path ansP=path;//先把path整体赋值给后继
    int i,now=0,xx,yy;

    //这里获取后继节点的方式为:对传入的path中的排列,随机交换排列中的两个位置对应的工件编号
    xx=rand()%n;
    yy=rand()%n;//获取两个随机位置
    //交换这两个位置的工件编号
    int temp=ansP.obj[xx];
    ansP.obj[xx]=ansP.obj[yy];
    ansP.obj[yy]=temp;

    //重新计算延时
    ansP.delay=0;
    for(i=0;i<n;i++)
    {
        int x=ansP.obj[i];
        if(now<J[x].a) now=J[x].a;
        now+=J[x].p;
        if(now>J[x].d) ansP.delay+=(now-J[x].d);
    }
    return ansP;//返回
}


//模拟退火
void SA()
{
    Init();//初始化

    //int k=1;
    int i;
    double t=T;//t为初始温度
    Path newPath=bestpath;//newPath作为后继
    srand((unsigned)(time(NULL)));//随机种子

    while(MIN_T<t){//当前温度大于最低温度时一直循环
        for(i=0;i<ILOOP;i++){//获取ILOOP个后继节点

            newPath=getNext(bestpath);//获取当前最优策略的后继
            double dE=(double)(newPath.delay-bestpath.delay);//计算后继与当前最优的delay差值

            if(dE<0){//dE为负,说明找到了更优策略,则更新最优
                bestpath=newPath;
            }
            else{//否则以一定概率跳出该最优,这个概率为exp(-dE/t)
                int rd=rand()%101;
                if(rd<(int)(exp(-dE/t)*100)){
                    bestpath=newPath;
                }
            }

        }

        //printf("No.%d : delay=%d\n",k++,bestpath.delay);

        t=t*DELATE;//温度降低
    }
}

int main()
{
    int i=0,x,y,z;
    freopen("ins2.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    scanf("%d",&n);
    while(i<n){//读取输入
        scanf("%d %d %d",&x,&y,&z);
        J[i].a=x;
        J[i].p=y;
        J[i].d=z;
        i++;
    }

    long start_time=clock();

    SA();//调用模拟退火算法

    long end_time=clock();

    //输出最优解
    printPath(bestpath);
    //输出SA算法运行时间
    printf("time = %ld ms\n",end_time-start_time);

    return 0;
}

结果:

这里写图片描述

整个迭代过程图示如下:

这里写图片描述

注:以上所有操作均在作者在网上搜集资料后,在个人电脑上实验成功,若读者实验时失败,可能由一些未知因素导致,可与作者联系。编写的教程可能由于疏忽出错,请与作者联系。

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值