关于二分图匹配的讲解见文章二分图匹配。
本文练习两个简单的二分图匹配,分别对应于文章中的dfs和bfs的Hungary算法。
1、HDU1150
题意:两台机器A和B,每台都有许多工作模式。有多个任务,每个任务可以在A机器的某个模式或者在B机器的某个模式完成。问最少需要重启几次机器。
分析:该问题即最小点覆盖,即选取最少的点,使任意一条边至少有一个端点被选择,任务相当于边。最小点覆盖数=最大匹配数。
代码(dfs):
#include <stdio.h>
#include <string.h>
#define N 102
int G[N][N];
int matching[N], check[N];
int n, m, k;
bool dfs(int u){
for(int i = 1; i <= m; i++){
if(G[u][i]!=-1 && !check[i]){
check[i] = 1;
if(matching[i] == -1 || dfs(matching[i])){
matching[i] = u;
return true;
}
}
}
return false;
}
int main(){
while(scanf("%d", &n) && n){
scanf("%d%d", &m, &k);
int a, b, c;
memset(G, -1, sizeof(G));
for(int i = 0; i < k; i++){
scanf("%d%d%d", &a, &b, &c);
if(b && c)
G[b][c] = a;
}
int cnt = 0;
memset(matching, -1, sizeof(matching));
for(int i = 1; i <= n; i++){
memset(check, 0, sizeof(check));
if(dfs(i))
cnt++;
}
printf("%d\n", cnt);
}
return 0;
}
2、POJ2446
题意:给一个n*m的表格,表格中有一些格子挖去,用1*2或者2*1的长方形去覆盖,判断是否恰好完全覆盖。
解析:首先需要根据给定的图重新建图,然后求最大匹配数,如果剩余的格子的是最大匹配数的两倍,那么可以完全覆盖。
代码(bfs):
#include <stdio.h>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
const int N = 32*32+5;
int tol, k;
int a[35][35];
int pre[N], matching[N], check[N];
vector<int>G[N];
queue<int> Q;
int nt[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
bool Hungary(){
int ans = 0;
memset(matching, -1, sizeof(matching));
memset(check, -1, sizeof(check));
for(int i = 1; i <= tol; i++){
if(matching[i] == -1){
while(!Q.empty())Q.pop();
Q.push(i);
pre[i] = -1;
bool flag = false;
while(!Q.empty() && !flag){
int u = Q.front();
Q.pop();
for(int j = 0; j < G[u].size() && !flag; j++){
int v = G[u][j];
if(check[v] != i){
check[v] = i;
Q.push(matching[v]);
if(matching[v] != -1){
pre[matching[v]] = u;
}else{
flag = true;
int d = u, e = v;
while(d != -1){
int t = matching[d];
matching[d] = e;
matching[e] = d;
d = pre[d];
e = t;
}
}
}
}
}
if(matching[i] != -1)ans++;
}
}
if((tol - k) / 2 == ans)return true;
return false;
}
int main(){
int x, y, n, m;
while(~scanf("%d%d%d", &n, &m, &k)){
memset(a, 0, sizeof(a));
for(int i = 0; i < k; i++){
scanf("%d%d", &y, &x);
a[x][y] = 1;
}
tol = n * m;
if((tol - k) % 2){
printf("NO\n");
continue;
}
for(int i = 1; i <= tol; i++)
G[i].clear();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
if(a[i][j] == 1)continue;
int nw = (i-1)*m + j;
for(int k = 0; k < 4; k++){
int nx = i + nt[k][0];
int ny = j + nt[k][1];
if(nx <= 0 || nx > n || ny <= 0 || ny > m)continue;
if(a[nx][ny] == 1)continue;
int p = (nx-1)*m + ny;
G[nw].push_back(p);
}
}
bool flag = Hungary();
if(flag)printf("YES\n");
else printf("NO\n");
}
return 0;
}