题目描述:
百度办公区里到处摆放着各种各样的零食。百度人力资源部的调研发现,员工如果可以在自己喜欢的美食旁边工作,工作效率会大大提高。因此,百度决定进行一次员工座位的大调整。
调整的方法如下:
1 . 首先将办公区按照各种零食的摆放分成 N 个不同的区域。(例如:可乐区,饼干区,牛奶区等等)。
2 . 每个员工对不同的零食区域有不同的喜好程度(喜好程度度的范围为 1 — 100 的整数, 喜好程度越大表示该员工越希望被调整到相应的零食区域)。
3 . 由于每个零食区域可以容纳的员工数量有限,人力资源部希望找到一个最优的调整方案令到总的喜好程度最大。
数据输入:
第一行包含两个整数 N , M ,( 1<=N , M<=300 )。分别表示 N 个区域和 M 个员工。
第二行是 N 个整数构成的数列 a ,其中 a[i] 表示第 i 个区域可以容纳的员工数, (1<=a[i]<=M , a[1]+a[2]+..+a[N]=M) 。
紧接着是一个 M*N 的矩阵 P , P ( i , j )表示第 i 个员工对第 j 个区域的喜好度。
答案输出:
对于每个测试数据,输出可以达到的最大的喜好程度。
输入样例:
3 3
1 1 1
100 50 25
100 50 25
100 50 25
输出样例:
175
数据解释:此数据只存在一种安排方法,三个员工分别安置在三个区域。最终的喜好程度为 100+50+25=175
my answer:
带权的二分匹配,只需调用模版即可
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
/*********************************************************/
//这些都是KM模板
const int N = 305;//二分图中每一个子图的点的最大数
const int INF = 1<<28;//正无穷
bool xckd[N], yckd[N];//在一次DFS中,Xi与Yi是否在交错树上
int n;//点的个案
int edge[N][N];//二维权值信息用矩阵来存储
int xmate[N], ymate[N];//保存匹配结果
int lx[N], ly[N];//Xi与Yi和标号,即解说中的A[]和B[]
int slack[N];//松弛量
int prev[N];//?
queue<int> Q;
bool bfs();//寻找增广路径
void agument(int);
int KMMatch();//KM算法
/*********************************************************/
int main()
{
int area[305], i, j, k, t;
while(cin>>m>>n)
{
for(i = 0; i < m; i++)
cin>>area[i];
int cnt = 0;
for(i = 0; i < n; i++)
{
cnt = 0;
for(j = 0; j < m; j++)
{
cin>>t;
for(k = 0; k < area[j]; k++)
{
edge[i][cnt] = t;
cnt++;
}
}
}
cout<<KMMatch()<<endl;
}
return 0;
}
bool bfs()
{
while(!Q.empty())
{
int p = Q.front(), u = p>>1;
Q.pop();
if(p&1)
{
if(ymate[u] == -1)
{
agument(u);
return true;
}
else
{
xckd[ymate[u]] = true;
Q.push(ymate[u]<<1);
}
}
else
{
for(int i = 0; i < n; i++)
{
if(yckd[i])continue;
else if(lx[u] + ly[i] != edge[u][i])
{
int ex = lx[u] + ly[i] - edge[u][i];
if(slack[i] > ex)
{
slack[i] = ex;
prev[i] = u;
}
}
else
{
yckd[i] = true;
prev[i] = u;
Q.push((i<<1)|1);
}
}
}
}
return false;
}
void agument(int u)
{
while(u != -1)
{
int pv = xmate[prev[u]];
ymate[u] = prev[u];
xmate[prev[u]] = u;
u = pv;
}
}
int KMMatch()
{
int i, j, mn;
memset(ly, 0, sizeof(ly));
for(i = 0; i < n; i++)
{
lx[i] = -INF;
for(j = 0; j < n; j++)
{
lx[i] = lx[i]>edge[i][j]?lx[i]:edge[i][j];
}
}
memset(xmate, -1, sizeof(xmate));
memset(ymate, -1, sizeof(ymate));
bool agu = true;
for(mn = 0; mn < n; mn++)
{
if(agu)
{
memset(xckd, 0, sizeof(xckd));
memset(yckd, 0, sizeof(yckd));
for(i = 0; i < n; i++)
slack[i] = INF;
while(!Q.empty())
Q.pop();
xckd[mn] = true;
Q.push(mn<<1);
}
if(bfs())
{
agu = true;
continue;
}
int ex = INF;
mn--;
agu = false;
for(i = 0; i < n; i++)
if(!yckd[i])
ex = ex<slack[i]?ex:slack[i];
for(i = 0; i < n; i++)
{
if(xckd[i])
lx[i] -= ex;
if(yckd[i])
ly[i] += ex;
slack[i] -= ex;
}
for(i = 0; i < n; i++)
if(!yckd[i] && slack[i] == 0)
{
yckd[i] = true;
Q.push((i<<1)|1);
}
}
int cost = 0;
for(i = 0; i < n; i++)
cost += edge[i][xmate[i]];
return cost;
}