二分图_HDOJ2853

Assignment
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1748 Accepted Submission(s): 940

Problem Description
Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of troops. The assignment is measure by efficiency, which is an integer, and the larger the better.
We have N companies of troops and M missions, M>=N. One company can get only one mission. One mission can be assigned to only one company. If company i takes mission j, we can get efficiency Eij.
We have a assignment plan already, and now we want to change some companies’ missions to make the total efficiency larger. And also we want to change as less companies as possible.

Input
For each test case, the first line contains two numbers N and M. N lines follow. Each contains M integers, representing Eij. The next line contains N integers. The first one represents the mission number that company 1 takes, and so on.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.

Output
For each the case print two integers X and Y. X represents the number of companies whose mission had been changed. Y represents the maximum total efficiency can be increased after changing.

Sample Input
3 3
2 1 3
3 2 4
1 26 2
2 1 3
2 3
1 2 3
1 2 3
1 2

Sample Output
2 26
1 2

题目大意:
一个公司里面有n个员工,m个任务,每一名员工做每一个人任务都有一个效益;现在给出了一种任务分配的方案。
问:效益最大是多少?在保证效益最大的前提下最少更改多少个员工的任务?

解题思路:
我们可以通过员工和任务构建一张二分图,边权就是每个员工对于每个任务的效益,然后通过求最优匹配得到最大的效益;
然后,我们可以给每一个题目给出的方案中的边的边权 * (n + 1) + 1,即ans = ans * (n + 1) + 1,让 其他的边权 * (n + 1), 即ans = ans * (n + 1),然后再对这张新的二分图求一次最优匹配会得到一个答案,设为ans2,并设原图中的答案为ans1;
则有 ans1 * (n+ 1) <= ans2 <= ans1 * (n + 1) + n;
当ans2取到最小值的时候表示最优方案中的边没有一条是原方案中的边,取到最大值的时候表示最有方案的边全部都是原方案的边。
这样,最优方案中选取原方案的边的个数 = ans2 % (n + 1),从而第二个问题的答案就等于 n - ans2 % (n + 1)。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 55;
const int inf = 0x3f3f3f3f;

int n, m, ans, ans1, ans2;
int w[maxn][maxn], la[maxn], lb[maxn], match[maxn];
bool vis[maxn][maxn], va[maxn], vb[maxn];
int delta;

inline bool find(int x) {
	va[x] = true;
	
	for(int y = 1; y <= m; y ++) {
		if(la[x] + lb[y] == w[x][y]) {
			if(!vb[y]) {
				vb[y] = true;
				if(!match[y] || find(match[y])) {
					match[y] = x;
					return true;
				}
			}
		}
	}
	
	return false;
}

inline void KM(void) {
	for(int i = 1; i <= n; i ++) {
		la[i] = inf;
		
		for(int j = 1; j <= m; j ++) {
			lb[j] = 0;
			la[i] = max(la[i], w[i][j]);
		}
	}
	
	memset(match, 0, sizeof match);
	ans2 = 0;
	
	for(int i = 1; i <= n; i ++) 
		while(true) {
			memset(va, false, sizeof va);
			memset(vb, false, sizeof vb);
			
			if(find(i)) break;
			
			delta = inf;
			for(int x = 1; x <= n; x ++)
			if(va[x])
			for(int y = 1; y <= m; y ++)
			if(!vb[y])
			delta = min(delta, la[x] + lb[y] - w[x][y]);
			
			for(int j = 1; j <= n; j ++)
			if(va[j]) la[j] -= delta;
			
			for(int j = 1; j <= m; j ++)
			if(vb[j]) lb[j] += delta;	
		} 
		
	for(int i = 1; i <= m; i ++) {
		int tmp = match[i];
		ans2 += w[tmp][i];
	}
}

int main(void) {
	//freopen("in.txt", "r", stdin);
	
	while(scanf("%d%d", &n, &m) != EOF) {
		ans = 0;
		//输入 
		for(int i = 1; i <= n; i ++)
			for(int j = 1; j <= m; j ++)
				scanf("%d", &w[i][j]);
				
		for(int i = 1; i <= n; i ++) {
			int j;
			scanf("%d", &j);
			ans += w[i][j];
			vis[i][j] = true;
		}
		
		KM();
		ans1 = ans2;
		
		for(int i = 1; i <= n; i ++)
			for(int j = 1; j <= m; j ++)
				if(vis[i][j]) w[i][j] = w[i][j] * (n + 1) + 1;
				else w[i][j] = w[i][j] * (n + 1);
		
		KM();
		
		int permt = n - ans2 % (n + 1);
		printf("%d %d\n", permt, ans1 - ans);
		
		memset(vis, false, sizeof vis);
	}	
	
	//fclose(stdin);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值