题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063

 

就是一个匈牙利模板题,纯模板:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1000 + 10;
int head[maxn], nextt[maxn * 2], to[maxn * 2], cnt = 2;
int n, k, m;
int vis[maxn], match[maxn];

void add(int u, int v) {
	to[cnt] = v; nextt[cnt] = head[u]; head[u] = cnt++;
}

bool Find(int x) {
	for (int i = head[x]; i != -1; i = nextt[i]) {
		int y = to[i];
		if (!vis[y]) {
			vis[y] = 1;
			if (!match[y] || Find(match[y])) {
				match[y] = x; return true;
			}
		}
	}
	return false;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	while (cin >> k && k) {
		cin >> n >> m;
		memset(match, 0, sizeof(match));
		memset(head,-1,sizeof(head));

		int u, v;
		for (int i = 1; i <= k; i++) {
			cin >> u >> v;
			add(u, v+n);
		}

		int ans = 0;
		for (int i = 1; i <= n; i++) {
			memset(vis,0,sizeof(vis));
			if (Find(i))ans++;
		}

		cout << ans << endl;
	}

	return 0;
}

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2236

基本就不会考裸的匈牙利算法,我们必须学会得去应用:

题意:

      这道题就是给你一个n阶方阵,从中选出n个数,这n个数的行和列都不相同(可以这样理解,一行只有一个数,一列也只有一个数),问这n个数的最大值与最小值的差值的最小值;

 

思路:

           如果是考虑搜索做法的话,很显然这是个个n!的复杂度,肯定实现不了。

           基于行和列不相同,把行作为一个集合,列作为一个集合,最后合理的选择其实就是一个二分图。

          之后我们枚举这个差值,用匈牙利算法判断是否合法。可是光知道差值还是不够啊,我们还得知道这些选出来数的范围啊。那我们就再枚举下界,这样就可以用匈牙利算法匹配了。然而这样的话算复杂度就是O(n^4)了。

这时候我们可以二分差值来降低复杂度。具体请参考代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 100 + 10;
int head[maxn], nextt[maxn * 2], to[maxn * 2], cnt = 2;
int n, a[110][110];
int vis[maxn], match[maxn];

void add(int u, int v) {
	to[cnt] = v; nextt[cnt] = head[u]; head[u] = cnt++;
}

bool Find(int x,int l,int r) {
	for (int i = 1; i <= n;i++) {
		if (!vis[i]) {
			if (a[x][i]<l || a[x][i]>r)continue;       //如果这个数不在范围内,说明x不能和i匹配
			vis[i] = 1;
			if (!match[i] || Find(match[i],l,r)) {
				match[i] = x; return true;
			}
		}
	}
	return false;
}

bool check(int l, int r) {
	memset(match, 0, sizeof(match));
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		memset(vis,0,sizeof(vis));
		if (Find(i,l,r))ans++;
	}
	return ans == n;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	int t; cin >> t;
	while (t--) {
		cin >> n;
		for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)cin >> a[i][j];

		int l = 0, r = 100;  //差值的上下界
		while (r > l) {
			int mid = (l + r)/2;
			bool f = false;
			for (int i = 1; i + mid <= 100; i++) {  //枚举范围的下届
				if (check(i, i + mid)) {        //匈牙利算法检查是否合法
					f = true;
					break;
				}
			}
			if (f)r = mid;          //匹配成功,降低上界
			else l = mid + 1;         //匹配失败,降低下届
		}
		
		cout << r << endl;
	}

	return 0;
}