题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1045
题意:
在一个用网格表示的城市中有若干个墙,还有可以向四方扫射的机枪,机枪的子弹可以可以打穿机枪,但不能打穿墙,给出城市的地图,计算可放置机枪的最大数目。
思路:
很容易想到的是使用搜索,穷举即可。但是这道题也可以巧妙的使用二分图匹配来做。分别按照横向和纵向将每行每列的连续空白区域标号,也就是缩点,然后在相交的空白区域之间连线,最后在该图上跑二分图最大匹配即可。
代码如下:
#include <cstring>
#include <vector>
#include <cstdio>
#define MAXV 20
#define fp(PP,QQ,RR) for(int PP = QQ;PP < RR;PP ++)
using namespace std;
int match[MAXV];
vector <int> G[MAXV];
bool used[MAXV];
void add_edge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
bool dfs(int v){
used[v] = 1;
fp(i,0,G[v].size()){
int u = G[v][i],w = match[u];
if(w < 0 || !used[w] && dfs(w)){
match[v] = u;
match[u] = v;
return 1;
}
}
return 0;
}
int bipartite_matching(int V){
int res = 0;
memset(match,-1,sizeof(match));
fp(v,0,V){
if(match[v] < 0){
memset(used,0,sizeof(used));
if(dfs(v)) res ++;
}
}
return res;
}
int main(void)
{
int n,num;
char city[10][10];
int r[4][4],c[4][4];
while(scanf("%d",&n) && n){
fp(i,0,n) scanf("%s",city[i]);
num = 0;
r[0][0] = 0;
fp(i,1,n * n){
if(i % n == 0 || city[i / n][i % n] == 'X' && city[(i - 1) / n][(i - 1) % n] == '.') num ++;
r[i / n][i % n] = num;
}
c[0][0] = ++ num;
fp(i,1,n * n){
if(i % n == 0 || city[i % n][i / n] == 'X' && city[(i - 1) % n][(i - 1) / n] == '.') num ++;
c[i % n][i / n] = num;
}
fp(i,0,n){
fp(j,0,n){
if(city[i][j] == '.'){
add_edge(r[i][j],c[i][j]);
}
}
}
printf("%d\n",bipartite_matching(num + 1));
fp(i,0,MAXV){
G[i].clear();
}
}
return 0;
}