http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1002
题目描述:对一个给定的n*n的地图,放入炮塔,使得它们之间不冲突。当它们在同一行或同一列时且中间没有障碍物,冲突。求最多能放入多少炮塔。
二分图匹配经典模型。
对每一行的联通块缩点放入x集合,每一列的联通块缩点放入y集合。若联通块之间有交点,连边。之后做一次最大匹配就可以求解。
当然由于n的范围小,可以直接搜索。
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 125
using namespace std;
int n ,cntx ,cnty ,cx[MAXN] ,cy[MAXN] ,tmp[15][15] ;
char map[15][15] ;
bool vis[MAXN<<1] ,flag[MAXN][MAXN];
void build()
{
memset(flag,0,sizeof flag);
memset(tmp,0,sizeof tmp);
cntx=1;
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
if(map[i][j]=='X')++cntx;
else tmp[i][j]=cntx;
if(map[i][n-1]!='X')++cntx;
}
cnty=1;
for(int j=0;j<n;++j)
{
for(int i=0;i<n;++i)
if(map[i][j]=='X')++cnty;
else flag[tmp[i][j]][cnty]=1;
if(map[n-1][j]!='X')++cnty;
}
}
bool dfs(int u)
{
for(int v=1;v<=cnty;++v)
if(!vis[v]&&flag[u][v])
{
vis[v]=1;
if(!cy[v]||dfs(cy[v]))
{
cx[u]=v ,cy[v]=u ;
return 1;
}
}
return 0;
}
void solve()
{
memset(cx,0,sizeof cx);
memset(cy,0,sizeof cy);
int ans=0;
for(int i=1;i<=cntx;++i)
if(!cx[i])
{
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<n;++i)
scanf("%s",map[i]);
build();
solve();
}
return 0;
}