题意:有个nXm的棋盘,"."表示可以放车(车是可以管一行和一列的,也就是它所在行和列只能有它一个),“X"表示墙,然后问你最多可以放多少个车,使得他们互相不会攻击。
思路:车是可以管一行一列,但是有x的话就会把它管的行和列截至在X处,然后我们就可以把每个行中的连续的点分块编号,对列做同样的操作,然后行的块号当X集合,列的块号当Y集合,然后对每一个“。”所在的行块号和列块号之间加一条边,然后求二分图最大匹配。
#include<stdio.h>
#include<string.h>
#define M 1007
int link[M*10],g1[M][M],g2[M][M],head[M*10];
bool vis[M*10];
char s[M][M];
int n,a,b,num;
struct E
{
int v,next;
}edg[M*M];
void addedge(int u,int v)
{
edg[num].v=v;edg[num].next=head[u];
head[u]=num++;
}
bool find(int i)
{
for(int j=head[i]; j!=-1; j=edg[j].next)
{
int v=edg[j].v;
if(!vis[v])
{
vis[v]=true;
if(!link[v]||find(link[v]))
{
link[v]=i;
return true;
}
}
}
return false;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(head,-1,sizeof(head));
num=0;
memset(link,0,sizeof(link));
int count=0;
for(int i=1; i<=n; i++)
scanf("%s",s[i]+1);
a=1,b=1;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(s[i][j]=='.')
{
g1[i][j]=s[i][j-1]!=s[i][j]?a++:g1[i][j-1];
g2[i][j]=s[i-1][j]!=s[i][j]?b++:g2[i-1][j];
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(s[i][j]=='.')addedge(g1[i][j],g2[i][j]);
for(int i=1; i<a; i++)
{
memset(vis,false,sizeof(vis));
if(find(i))count++;
}
printf("%d\n",count);
}
return 0;
}