二分圖_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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章