C/C++分支限界法-作业调度问题

问题描述:给定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.运行结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值