在一个n*n的图中,‘X’代表卒,在‘.’的地方放置尽量多的车,使得它们不互相攻击。问最多可放置车的数目。
和Fire Net一样,但这里图是100*100的,搜索会超时(其实我还脑残的试了试).
正解是二分图匹配,将每行中连续为.的作为X集合中一个点,同样,将每列中连续为.的点作为Y集合中的一个点。对原图中每个'.',将其对应的X集合和Y集合中的标号建边,便形成了二分图,对该图求最大匹配,每形成一个匹配即选择该点放车,那么与它相同编号的行和列都被覆盖了,都不能被选择了。最大匹配数就是最多可以放的车数。
#include <stdio.h>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#define LL long long
#define _LL __int64
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 50010;
struct node
{
int v;
int next;
}edge[10010];
char G[110][110];
int mapr[110][110],mapc[110][110];
int n;
int cnt,pre[10010];
int a,b;
int match[10010];
int chk[10010];
void add(int u,int v)
{
edge[cnt] = ((struct node){v,pre[u]});
pre[u] = cnt++;
}
void init()
{
int i,j;
a = 1,b = 1;
memset(mapr,0,sizeof(mapr));
memset(mapc,0,sizeof(mapc));
cnt = 0;
memset(pre,-1,sizeof(pre));
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(G[i][j] == '.')
{
if(G[i][j] != G[i][j-1])
mapr[i][j] = a++;
else mapr[i][j] = mapr[i][j-1];
}
}
}
for(int j = 1; j <= n; j++)
{
for(int i = 1; i <= n; i++)
{
if(G[i][j] == '.')
{
if(G[i][j] != G[i-1][j])
mapc[i][j] = b++;
else mapc[i][j] = mapc[i-1][j];
}
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(G[i][j] == '.')
add(mapr[i][j], mapc[i][j]);
}
}
}
int dfs(int p)
{
for(int i = pre[p]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(!chk[v])
{
chk[v] = 1;
if(match[v] == -1 || dfs(match[v]))
{
match[v] = p;
return 1;
}
}
}
return 0;
}
int main()
{
while(~scanf("%d",&n))
{
memset(G,'0',sizeof(G));
for(int i = 1; i <= n; i++)
scanf("%s",G[i]+1);
init();
memset(match,-1,sizeof(match));
int ans = 0;
for(int i = 1; i <= a; i++)
{
memset(chk,0,sizeof(chk));
ans += dfs(i);
}
printf("%d\n",ans);
}
return 0;
}