问题描述:任务分配问题要求把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();
}
运行结果: