问题描述:给定n个作业集合J={J1,J2,…,Jn},每个作业都有3项任务分别在3台机器上完成,作业Ji需要机器j的处理时间为tij(1<=i<=n,1<=j<=3),每个作业必须要先有机器1处理,再由机器2处理,最后由机器3处理。批处理作业调度问题要求确定这n个作业的最优处理顺序,使得从第一个作业再机器1上处理开始,到最后一个作业再机器3上处理结束所需的时间最少。
例:
作业-机器矩阵为
问题示例:
这些任务的一个执行序列为:
1.确定上界,这些任务的一个随机执行顺序即可作为一个上界,例如执行顺序为1,2,3,4,则up=5+7+9+2+5+10=38。
2.确定目标函数,假设sum1为完成k个任务在机器1上的处理时间,sum2为完成k个任务在机器2上的处理时间,i=k+1,现需要处理第k+1个任务,则目标函数lb求法为:
sum1[k+1]=sum[k]+ti1;
sum2=max(sum1[k+1],sum2[k])+ti2;
lb=sum2+剩余任务在机器2上执行时间总和+剩余任务在机器3上执行时间中的最短时间。
3.可以在分支节点上建立一个数组保存执行序列,在只剩下1个任务未执行情况下根据目标函数值大小即可确定最优解序列。
4.图解:
5.完整代码:
#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;
#define max_m 3 //最大机器数
#define max_t 5 //最大任务数
#define INF 1000
int n; //实际任务数
int t_m[max_t][max_m]; //存储机器与任务的矩阵
typedef struct Node
{
int sum1;
int sum2;
int lb;
int t_num; //已执行任务数
int t; //当前任务
bool visited[max_t]; //标记已执行任务
int es[max_t]; //执行序列
bool operator < (const Node &p)const
{
return p.lb<lb;
}
}Node;
priority_queue<Node> pp;
int up;
void get_up() //获取上界,任务从1到4按序执行
{
up=0;
for(int i=0;i<max_t;i++)
up+=t_m[i][max_m-1];
for(int j=0;j<max_m-1;j++)
up+=t_m[0][j];
}
int get_lb(Node node) //获取目标函数值
{
node.lb=node.sum2;
int min=INF;
for(int i=0;i<n;i++)
if(!node.visited[i])
{
if(i!=node.t)
{
node.lb+=t_m[i][1]; //加上剩余任务在第二个机器上完成时间和
if(t_m[i][2]<min)
min=t_m[i][2];
}
}
node.lb+=min; //加上剩余任务中执行时间最短的一个
return node.lb;
}
void solve()
{
get_up();
int sequence[max_t];
Node first; //初始化第一个节点
first.t_num=0;
first.lb=0;
first.t=-1;
first.sum1=0;
first.sum2=0;
for(int i=0;i<n;i++)
first.visited[i]=false;
for(int j=0;j<n;j++)
first.es[j]=-1;
pp.push(first);
while(pp.size())
{
Node tmp=pp.top();
pp.pop();
if(tmp.t_num==n-1)
{
int ans;
for(int i=0;i<n;i++)
{
sequence[i]=tmp.es[i];
if(!tmp.visited[i]) //找到最后一个未执行任务
ans=i;
}
sequence[n-1]=ans;
break;
}
else
{
Node next;
for(int i=0;i<n;i++)
next.visited[i]=false;
for(int i=0;i<n;i++)
{
if(!tmp.visited[i])
{
next.t_num=tmp.t_num+1;
next.t=i;
for(int j=0;j<n;j++) //继承执行序列
next.es[j]=tmp.es[j];
next.es[next.t_num-1]=i;
next.sum1=tmp.sum1+t_m[i][0];
if(next.sum1>tmp.sum2)
next.sum2=next.sum1+t_m[i][1];
else
next.sum2=tmp.sum2+t_m[i][1];
for(int j=0;j<n;j++)
next.visited[j]=tmp.visited[j]; //继承任务操作标记
next.visited[i]=true;
next.lb=get_lb(next);
if(next.lb<=up)
{
pp.push(next);
}
}
}
}
}
printf("最优解任务执行序列为:");
for(int i=0;i<n;i++)
printf("%d ",sequence[i]+1);
}
main()
{
printf("请输入任务数:");
scanf("%d",&n);
printf("请输入任务-机器矩阵:\n");
for(int i=0;i<n;i++)
for(int j=0;j<max_m;j++)
{
scanf("%d",&t_m[i][j]);
if(j==max_m-1)
getchar();
}
solve();
}
6.运行结果: