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

题目描述: 

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

调整的方法如下: 

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

. 每个员工对不同的零食区域有不同的喜好程度(喜好程度度的范围为 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值