C/C++分支限界法-任务分配问题

问题描述:任务分配问题要求把n个任务分配给n个人,每个人完成每项任务的成本不同,要求分配总成本最小的分配方案。

: 任务分配矩阵如下
在这里插入图片描述
1.取每行最小值作为目标函数下界,即down=2+3+1+4=10;
用贪心算法选取目标函数上界,即up=2+3+5+4=14。
2.确定目标函数:
lb=已分配任务员工总成本+未分配员工最小成本之和
3.分配到第三个员工即可初步判断最优解,若总成本不大于目标函数值,则该成本为最优解,否则可通过更新上界进一步缩小搜索最优解范围。

图解
在这里插入图片描述
本题采用优先队列解,图中序号为出队列序号,画叉地方表示目标函数值大于上界,入队列失败。

完整代码

#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;
#define maxtask 10
#define INF 1000;     
int task[maxtask][maxtask];    //员工-任务表 
int n;                       //任务数 
int down;                     //下界 
int up;                       //上界 
typedef struct Node
{
	int v;          //已消耗成本 
	int lb;        //目标函数值 
	int c;         //执行人 
	int t;         //任务 
	int visited[maxtask];    //标记已分配任务 
	bool operator < (const Node &p)const
	{
		return p.lb<lb;
	}
 }Node;
 priority_queue<Node> pp;
void get_down()           //求下界 
{
	down=0;
	for(int i=0;i<n;i++)
	{
		int min=INF;
		for(int j=0;j<n;j++)
		{
			if(task[i][j]<min)
			min=task[i][j];
		}
		down+=min;
	}
	return;
}
void get_up()           //求上界 
{
	up=0;
	int visited[n];
	for(int i=0;i<n;i++)
	visited[i]=false;
	int flag=-1;
	for(int i=0;i<n;i++)
	{
		int min=INF;
		for(int j=0;j<n;j++)
		{
			if(!visited[j]&&task[i][j]<min)
			{
				min=task[i][j];
				flag=j;
			}	
		}
		up+=min;
		visited[flag]=true;
	}
	return;
}
int get_lb(Node node)         //获取目标值 
{
	node.lb=node.v;
	for(int i=node.c+1;i<n;i++)
	{
		int min=INF;
		for(int j=0;j<n;j++)
		{
			if(task[i][j]<min)
			min=task[i][j];
		}
		node.lb+=min; 
	 } 
	 return node.lb; 
}
void solve()
{
	get_down();
	get_up();
	Node first;    //初始化第一个节点 
	first.c=-1;
	first.lb=down;
	first.t=-1;
	first.v=0;
	for(int i=0;i<n;i++)
	first.visited[i]=false;
	pp.push(first);
	int ret=INF;
	while(pp.size())
	{
		Node tmp=pp.top();
		pp.pop();
		if(tmp.c==n-2)
		{
			int min=INF;
			for(int i=0;i<n;i++)
			{
				if(!tmp.visited[i]&&task[n-1][i]<min)
				min=task[n-1][i];
			}
			int ans=tmp.v+min;
			if(ans<=tmp.lb)         //总成本小于所有目标函数值则该值为最优解 
			{
				ret=ans;
				break;
			}
			else
			{
				if(ans<up)          //更新上界 
				up=ans;
				if(ans<ret)
				ret=ans;
				continue;
			}
		}
		Node next;                 //加入节点 
		for(int i=0;i<n;i++)
		next.visited[i]=false;
		for(int j=0;j<n;j++)
		{
			if(!tmp.visited[j])
			{
				next.c=tmp.c+1;
				next.t=j;
				next.v=tmp.v+task[next.c][j];	
				for(int i=0;i<n;i++)
				next.visited[i]=tmp.visited[i];
				next.visited[j]=true;
				next.lb=get_lb(next);
				if(next.lb<=up)
				{
						
					pp.push(next);
				}
				
			}
		}
	}
	printf("最优解为:%d\n",ret);
	return;
}
main()
{
    printf("请输入任务数:");
    scanf("%d",&n);
    printf("请录入工作信息,行(员工),列(任务):\n");
    for(int i=0;i<n;i++)
    {
    	 for(int j=0;j<n;j++)
    {
    	scanf("%d",&task[i][j]);
	}
	getchar();
	}
  solve();
}

运行结果
在这里插入图片描述

  • 22
    点赞
  • 156
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值