匈牙利算法
匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法
该算法是求解二分图的完全匹配问题
建图:把行号放左边点集,列号放在右边点集。
关键是求该二分图的最小边覆盖点集使得每条边都被至少一个点覆盖。
算法模板:
//使用bfs实现 int dfs(int e) { for(int i = 1; i <= v; ++i) { if(a[e][i] && !vis[i]) { vis[i] = 1; if(match[i] == -1 || dfs(match[i])) {//十分重要 match[i] = e;//在二分图中: 行e与列i 连线 return 1; } } } return 0; }
例题1
POJ3401
input: 3 4 1 1 1 3 2 2 3 2 output: 2
问题描述:在N*N的矩阵里面,有k个星球。有一个神奇的武器,每次可以消灭一行或者一列的星球,问最少使用多少次武器可以消灭所有的星球。
求解代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> using namespace std; int u; int p[1100][1100]; int match[1100]; int vis[1100]; int dfs(int e) { //匈牙利算法 for(int i = 1; i <= u; ++i) { if(p[e][i] && !vis[i]) { vis[i] = 1; if(dfs(match[i]) || match[i] == -1) { match[i] = e; return 1; } } } return 0; } int main () { int n, k; while(~scanf("%d%d", &n, &k)) { u = n; int ans = 0; memset(p, 0, sizeof p); memset(match, -1, sizeof match); for(int i = 1; i <= k; ++i) { int x, y; scanf("%d%d", &x, &y); p[x][y] = 1; } for(int i = 1; i <= n; ++i) { memset(vis, 0, sizeof vis); if(dfs(i)) ans++; } printf("%d ", ans); } }
例题2
Hdu 2119
input: 3 3 0 0 0 1 0 1 0 1 0 0 output: 2
题意:与上题类似,不多累述
求解代码:
#include <bits/stdc++.h> using namespace std; int u, v; bool a[110][110]; bool vis[110]; int match[110]; int dfs(int e) { for(int i = 1; i <= v; ++i) { if(a[e][i] && !vis[i]) { vis[i] = 1; if(match[i] == -1 || dfs(match[i])) {//十分重要 match[i] = e; return 1; } } } return 0; } int main () { int n, m; while(1) { cin >> n; if(n == 0) { break; } cin >> m; memset(a, 0, sizeof a); memset(match, -1, sizeof match); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { cin >> a[i][j]; } } u = n; v = m; int ans = 0; for(int i = 1; i <= u; ++i) { memset(vis, 0, sizeof vis); if(dfs(i)) { ans++; } } cout << ans << endl; } }