2006年百度之星程序设计大赛试题初赛题目-题5-座位调整

针对百度办公区员工座位调整问题,通过将办公区分成不同零食区域,并考虑员工对各区域的喜好程度,使用带权二分匹配算法(KM算法)找到使总喜好程度最大的座位分配方案。

题目描述: 

百度办公区里到处摆放着各种各样的零食。百度人力资源部的调研发现,员工如果可以在自己喜欢的美食旁边工作,工作效率会大大提高。因此,百度决定进行一次员工座位的大调整。 

调整的方法如下: 

. 首先将办公区按照各种零食的摆放分成 个不同的区域。(例如:可乐区,饼干区,牛奶区等等)。 

. 每个员工对不同的零食区域有不同的喜好程度(喜好程度度的范围为 1 — 100 的整数, 喜好程度越大表示该员工越希望被调整到相应的零食区域)。 

. 由于每个零食区域可以容纳的员工数量有限,人力资源部希望找到一个最优的调整方案令到总的喜好程度最大。 

数据输入: 

第一行包含两个整数 , ,( 1<=N , M<=300 )。分别表示 个区域和 个员工。 

第二行是 个整数构成的数列 ,其中 a[i] 表示第 个区域可以容纳的员工数, (1<=a[i]<=M , a[1]+a[2]+..+a[N]=M) 。 

紧接着是一个 M*N 的矩阵 , ( , )表示第 个员工对第 个区域的喜好度。 

答案输出: 

对于每个测试数据,输出可以达到的最大的喜好程度。 

输入样例: 

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; }

转载于:https://www.cnblogs.com/windmissing/archive/2012/05/18/2559825.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值