对应POJ题目:点击打开链接
题意:‘*’表示城市,“o”表示空地,一个天线只能把上下左右2个相邻的城市圈起来,问至少需要多少个天线才能把所有的城市圈起来。
例1的前2行使之变成
0 0 0 1 2 0 0 0 0
3 4 0 0 6 0 0 0 7
把非0的上下左右相邻的城市连起来,即G[1][2] = 1,G[2][1] = 1, G[3][4] = 1等等;在求最大匹配时,由于是无向边,故要Max/2。于是结果就是
城市数 - 最大匹配/2。
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#define ms(x,y) memset(x,y,sizeof(x))
const int MAXN=1000+10;
const int INF=1<<30;
using namespace std;
int G[50][20];
int net[410][410];
int link[410];
int vis[410];
int cnt;
int dfs(int u)
{
for(int v=1; v<=cnt; v++){
if(!vis[v] && net[u][v]){
vis[v] = 1;
if(link[v] == -1 || dfs(link[v])){
link[v] = u;
return 1;
}
}
}
return 0;
}
int MaxMatch()
{
int res = 0;
ms(link, -1);
for(int i=1; i<=cnt; i++){
ms(vis, 0);
if(dfs(i)) res++;
}
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d", &T);
while(T--)
{
ms(net, 0);
cnt = 0;
int r,c;
scanf("%d%d", &r,&c);
for(int i=1; i<=r; i++){
char str[20];
scanf("%s", str);
for(int j=1; j<=c; j++){
if(str[j-1] == '*') G[i][j] = ++cnt;
else G[i][j] = 0;
}
}
for(int i=1; i<=r; i++){
for(int j=1; j<=c; j++){
int u = G[i][j];
int v1 = G[i-1][j];
int v2 = G[i+1][j];
int v3 = G[i][j-1];
int v4 = G[i][j+1];
if(v1) net[u][v1] = 1;
if(v2) net[u][v2] = 1;
if(v3) net[u][v3] = 1;
if(v4) net[u][v4] = 1;
}
}
int ans = cnt - MaxMatch()/2;
printf("%d\n", ans);
}
return 0;
}