HDU 1045 Fire Net
二分匹配飘过
好久没有写过二分匹配的题目了,今天写了一个,有点手生,好长时间才建出图来。
建图方法:横竖分区。先看每一列,同一列相连的空地同时看成一个点,显然这样的区域不能够同时放两个点。这些点作为二分图的X部。同理在对所有的行用相同的方法缩点,作为Y部。
连边的条件是两个区域有相交部分。最后求最大匹配就是答案。
比如样例一:
4
.X..
....
XX..
....
得到两种编号为
以列缩点:
1 0 2 3
1 4 2 3
0 0 2 3
5 6 2 3
1 0 2 2
3 3 3 3
0 0 4 4
5 5 5 5
好了,其余不解释。
代码
/*
* File: HDU 1045 Fire Net
* Author: xiaotian @ hnu
* Created on 2010年10月14日, 下午7:28
* 题解:二分匹配水题,飘过,水水更健康
*/
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<set>
#include<math.h>
using namespace std;
#define N 20
#define inf 0x7ffffff
int n, m;
int g[N][N];
int x[N],y[N];
int chk[N];
char mp[5][5];
int a[5][5], b[5][5];
int dfs(int u) {
int v;
for (v = 0; v < m; v++)
if (g[u][v] && !chk[v]) {
chk[v] = 1;
if (y[v] == -1 || dfs(y[v])) {
y[v] = u; x[u] = v;
return 1;
}
}
return 0;
}
int maxmatch() {
int u, ret = 0;
memset(x, -1, sizeof (x));
memset(y, -1, sizeof (y));
for (u = 0; u < n; u++)
if (x[u] == -1) {
memset(chk, 0, sizeof (chk));
ret += dfs(u);
}
return ret;
}
int main() {
while (scanf("%d", &n), n) {
for (int i = 0; i < n; i++) scanf("%s", mp[i]);
memset(g, 0, sizeof (g)); memset(a, -1, sizeof (a)); memset(b, -1, sizeof (b));
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (mp[i][j] == '.' && a[i][j] == -1) {
for (int k = i; mp[k][j] == '.'&& k < n; k++) a[k][j] = cnt1;
cnt1++;
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (mp[i][j] == '.' && b[i][j] == -1) {
for (int k = j; mp[i][k] == '.'&& k < n; k++) b[i][k] = cnt2;
cnt2++;
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (mp[i][j] == '.') g[a[i][j]][b[i][j]] = g[b[i][j]][a[i][j]] = 1;
n = cnt1; m = cnt2;
printf("%d\n", maxmatch());
}
return 0;
}


浙公网安备 33010602011771号