链接:
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\n", tol-hungary()/2);
}
return 0;
}
来源:https://www.cnblogs.com/YY56/p/4722170.html