百度之星2006年初赛 座位调整

 

 1366:座位调整

Time Limit:1000MS  Memory Limit:65536K
Total Submit:3 Accepted:2 Page View:20

[Submit]   [Status]   [Discuss]

Font Size: Aa Aa Aa

Description

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



调整的方法如下:

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

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

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

Input

第一行包含两个整数N,M(N>=1,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个区域的喜好程度.

Output

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

Sample Input

3 3

1 1 1

100 50 25

100 50 25

100 50 25

Sample Output

175

Hint

此数据只存在一种安排方法,三个员工分别安置在三个区域。最终的喜好程度为100+50+25=175

Source

Astar2006 初赛
 
做法就是KM算法
我的建图过程如下:
把食品供应点拆开,不要让他成为一个点,如果一个食品供应点能够供应2个人,那就把它拆开成两个点,由于食品供应点的所有人数之和是等于员工数的,所以刚好构成一个两边点数一样的一个二分图,然后从员工到供应点连边的边权就是喜好度,然后再用KM算法进行最大带权匹配就好了,最后建的图是一个M*M的矩阵,由于M小于300,所以KM算法能够过。
也见到过别人用DP过掉的,不过没有想通。。DP一直很弱。。
话说我已经退役了,这个博客很少用了。。
 
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define inf 99999999
#define maxn 305

using namespace std;

int n,m;
int a[maxn];
int map[maxn][maxn];
int temp[maxn][maxn];
int link[maxn];
int lx[maxn],ly[maxn];
bool x[maxn],y[maxn];


bool dfs(int u)
{
	int i;
	x[u]=true;
	for(i=1;i<=n;i++)
	{
		if(lx[u]+ly[i]==map[u][i]&&!y[i])
		{
			y[i]=true;
			if(link[i]==-1||dfs(link[i]))
			{
				link[i]=u;
				return true;
			}
		}
	}
	return false;
}

int main()
{
	int i,j,k,num;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		for(i=1;i<=m;i++)
			scanf("%d",&a[i]);
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)
				scanf("%d",&temp[i][j]);
		for(i=1;i<=n;i++)
		{
			num=0;
			for(j=1;j<=m;j++)
			{
				for(k=1;k<=a[j];k++)
				{
					num++;
					map[i][num]=temp[i][j];
				}
			}
		}
		memset(x,0,sizeof(x));
		memset(y,0,sizeof(y));
		memset(link,-1,sizeof(link));
		memset(ly,0,sizeof(ly));
		for(i=0;i<maxn;i++)
			lx[i]=inf;
		for(k=1;k<=n;k++)
		{
			while(1)
			{
				memset(x,0,sizeof(x));
				memset(y,0,sizeof(y));
				if(dfs(k))
					break;
				int d=inf;
				for(i=1;i<=n;i++)
					if(x[i])
						for(j=1;j<=n;j++)
							if(!y[j]&&lx[i]+ly[j]-map[i][j]<d)
								d=lx[i]+ly[j]-map[i][j];
				for(i=1;i<=n;i++)
					if(x[i])
						lx[i]=lx[i]-d;
				for(i=1;i<=n;i++)
					if(y[i])
						ly[i]=ly[i]+d;
			}
		}
		int ans1=0,ans2=0;
		for(i=1;i<=n;i++)
			ans1=ans1+map[link[i]][i];
		printf("%d\n",ans1);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值