链接:
http://poj.org/problem?id=3020
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82834#problem/H
首先分别对顶点进行编号:空地用0表示.
1002
3400
0056
7890
接下来划分顶点集合
集合u:
1 2 4 5 8
集合v:
3 6 7 9
问题就是求这两个集合之间的最小路径覆盖.
最小路径覆盖 = 顶点个数 - 最大匹配数
建图时为了方便,如果顶点u和顶点v相邻,就认为g[u][v] = 1和g[v][u] = 1.也就是说两个顶点集都是由全部顶点组成的,这样求出来的最大匹配数将翻倍,所以最后计算的时候要除以2.
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 510 #define INF 0x3f3f3f3f // un是匹配左边的定点数, vn是匹配右边的定点数 int n, m, un, vn, used[N], p[N], hash[N][N], g[N][N]; char G[N][N]; //匈牙利算法, 从左边开始找增广路 int Find(int u) { for(int j=0; j<vn; j++) { if(!used[j] && g[u][j]) { used[j] = 1; if(p[j]==-1 || Find(p[j])) { p[j] = u; return true; } } } return false; } //最大匹配数 int hungary() { int ans = 0; memset(p, -1, sizeof(p)); for(int i=0; i<un; i++) { memset(used, 0, sizeof(used)); if(Find(i)) ans++; } return ans; } int main() { int t; scanf("%d", &t); while(t--) { int i, j, tol=0; scanf("%d%d", &n, &m); memset(G, 0, sizeof(G)); memset(hash, 0, sizeof(hash)); memset(g, 0, sizeof(g)); for(i=0; i<n; i++) { scanf("%s", G[i]); for(j=0; j<m; j++) if(G[i][j]=='*') hash[i][j]=tol++; } for(i=0; i<n; i++) for(j=0; j<m; j++) { if(G[i][j]=='*') { if(i>0 && G[i-1][j]=='*') g[hash[i][j]][hash[i-1][j]]=1; if(i<n-1 && G[i+1][j]=='*') g[hash[i][j]][hash[i+1][j]]=1; if(j>0 && G[i][j-1]=='*') g[hash[i][j]][hash[i][j-1]]=1; if(j<m-1 && G[i][j+1]=='*') g[hash[i][j]][hash[i][j+1]]=1; } } un = vn = tol; printf("%d ", tol-hungary()/2); } return 0; }