回溯法 批处理作业调度问题
Posted JeffCoding
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回溯法 批处理作业调度问题相关的知识,希望对你有一定的参考价值。
问题:
给定n个作业的集合J1,J2,…,Jn。每个作业必须先由机器1处理,然后由机器2处理。作业Ji需(1≤i≤n)要机器j(1≤j≤2)的处理时间为 tji。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。所有作业在机器2上完成处理的时间和称为 该作业调度的完成时间和。
要求对于给定的n个作业,制定最佳作业调度方案,使其完成时间和达到最小。
tji | 机器1 | 机器2 |
---|---|---|
作业1 | 2 | 1 |
作业2 | 3 | 1 |
作业3 | 2 | 3 |
分析:
由于机器有两个,每个作业必须从机器1处理,再到机器2处理,所以会两个作业同时处理,例如对上面的表格按照(1,2,3)的顺序调度:
(括号内代表作业序号)
机器1 机器2
2(1)
3(2) 1(1)
2(3) 1(2)
3(3)
每一个作业的处理时间 = 机器2的处理时间 + 机器2等待处理的时间(包括了之前作业的时间 和 本作业在机器1处理的时间)
所以我们求作业的处理时间,就是求该作业从开始到机器2处理完的时间:
作业1的处理时间:2+1 = 3
作业2的处理时间:2 + 3 + 1 = 6 (作业1的在机器1的处理时间,作业2的在机器1的处理时间 和 作业1在机器2的处理时间的较大时间(因为两者是同时进行的),作业2在机器2的处理时间)
作业3的处理时间:2 + 3 + 2 + 3 = 10所以(1,2,3)顺序的作业调度得到的作业调度时间为19
再看问题,问题要求得到最优作业调度方案和最小调度时间,也就是要得到使作业调度时间最小的作业处理顺序
因此这是一个 排列树 的问题,用排列树的算法框架:
代码实现
排列树的算法框架有两种实现方式:
(1)用visted方式
#define MAX 200
#include<iostream>
using namespace std;
int number;//作业数量
int x1[10];//作业在机器1运行的时间
int x2[10];//作业在机器2运行的时间
int sum = 0;//作业完成的总时间
int bestsum = MAX;//作业完成的最优时间
int order[10];//作业完成的次序,要用于交换
int bestorder[10];//作业完成的最优的顺序
int f1 = 0;//机器1累计的时间
int f2[10];//作业在机器2处理完累计的时间,即每一个作业的调度时间
int vis[10];//记录作业以否已被选
void backtrack(int cur) //cur表示正在赋值的位置,cur+1去到下一层子节点,i递增,在当前层遍历兄弟节点
if(cur>number)
for(int i=1; i<=number; i++) bestorder[i]=order[i];
bestsum=sum;
else
for(int i=1; i<=number; i++) //遍历number,尝试填第一位
if(!vis[i])
vis[i] = 1;
f1+=x1[i];
//本作业的在机器1的处理时间 和 上一个作业在机器2的处理时间的较大时间(因为两者是同时进行的)
f2[cur]=( f2[cur-1] > f1 ? f2[cur-1] : f1) + x2[i];
sum+=f2[cur];
order[cur] = i;
if(sum<bestsum) //剪枝,如果当前sum都大于bestsum了,则不再遍历此节点
backtrack(cur+1);
//每计算一次,为了不影响父节点和兄弟节点,运算完都要复位
sum-=f2[cur];
f1-=x1[i];
vis[i] = 0;
int main()
cout << "请输入作业的数量: ";
cin >> number;
int i;
cout << "请输入每个作业在机器1的运行时间:" << endl;
for(i=1; i<=number; i++)
cin >> x1[i];
cout << endl << "请输入每个作业在机器2的运行时间:" << endl;
for(i=1; i<=number; i++)
cin >> x2[i];
//初始化第一个序列,从1开始到number
for(i=1; i<=number; i++)
order[i] = i;
backtrack(1);
cout<<"最节省的时间为:"<<bestsum<<endl;
cout<<"对应的方案为:";
for(i=1;i<=number;i++) cout<<bestorder[i]<<" ";
cout<<endl;
(2)用swap交换方式
除了backtrack,其它代码都没有改变,只贴出backtranck函数的代码:
void backtrack(int cur)
//到达边界
if(cur > number)
for(int i=1; i<=number; i++)
bestorder[i] = order[i];
bestsum = sum;
else
//cur表示正在赋值的位置,cur+1去到下一层子节点,i递增,在当前层遍历兄弟节点
for(int i=cur; i<=number; i++)
f1 += x1[order[i]];
f2[cur] = (f2[cur - 1] > f1 ? f2[cur -1] : f1) + x2[order[i]];
sum += f2[cur];
/*例如cur为2,i=3时,表示正在为作业队列的第2个位置赋作业3的值,所以此时的队列作业顺序应该是1,3,2, 所以要把i和cur的位置换掉;
同理例如cur为1,i=2时,表示正在为作业队列的第1个位置赋作业2的值,此时的顺序是2,1,3,好好理解这一点
swap函数就是要做这个事情
*/
swap(order[cur], order[i]);
if(sum < bestsum)//剪枝,如果当前sum都大于bestsum了,则不再遍历此节点
backtrack(cur+1);
swap(order[cur], order[i]);
sum -= f2[cur];
f1 -= x1[order[i]];
输入上面表格的数据,得出结果:
以上是关于回溯法 批处理作业调度问题的主要内容,如果未能解决你的问题,请参考以下文章