题目链接: uva 12530
题目大意: 给出50x50的地图,地图上某些点不能走,可以走四个方向
Alice选任意一个点开始,然后和Bob轮流走,重复的点不能走
最后轮到谁走却不能移动棋子就输
解题思路: 二分图的完美匹配:最大匹配数刚好覆盖完左右集合的顶点
若图存在完美匹配,先手选择任意点,后手都选择与其匹配的点,先手必输
若图不存在完美匹配,先手选择不属于最大匹配的点,先手必胜
找出所有的连通块,进行黑白染色,即选择某点染黑,周围点染白
判断是否有一个块不存在完美匹配的,若存在先手选它则必胜
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 53
char Map[MAX][MAX];
int Co[MAX][MAX],F[MAX][MAX],n,m,an;
int cx[MAX*MAX],cy[MAX*MAX],visit[MAX*MAX],Index;
int Fx[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
struct snode{
int x,y;
}ans[MAX*MAX];
struct node{
int to,next;
}Edge[100000];
int pre[MAX*MAX];
void Add_edge(int a,int b)
{
Edge[Index].to=b;
Edge[Index].next=pre[a];
pre[a]=Index++;
}
void Color(int x,int y,int k) //不同的连通块黑白染色
{
int i,xx,yy;
Map[x][y]='X';
Co[x][y]=k;
ans[an].x=x,ans[an++].y=y;
F[x][y]=an;
for(i=0;i<4;i++)
{
xx=Fx[i][0]+x;
yy=Fx[i][1]+y;
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&Map[xx][yy]=='.')
Color(xx,yy,-k);
}
}
int DFS(int u,int an) //匈牙利最大匹配
{
int i,v;
for(i=pre[u];i!=-1;i=Edge[i].next)
{
v=Edge[i].to;
if(!visit[v])
{
visit[v]=1;
if(!cy[v]||DFS(cy[v],an))
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
}
return 0;
}
int Solve()
{
int i1,j1,x,y,xx,yy,t;
Index=0; //***
memset(pre,-1,sizeof(pre));
for(i1=0;i1<an;i1++)
{
x=ans[i1].x;
y=ans[i1].y;
t=Co[x][y];
for(j1=0;j1<4;j1++)
{
xx=Fx[j1][0]+x;
yy=Fx[j1][1]+y;
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&Co[xx][yy]==-t)
{
Add_edge(F[x][y],F[xx][yy]); //***
Add_edge(F[xx][yy],F[x][y]); //***
}
}
}
memset(cx,0,sizeof(cx));
memset(cy,0,sizeof(cy));
for(i1=1,t=0;i1<=an;i1++)
{
if(!cx[i1]) //x匹配y
{
memset(visit,0,sizeof(visit));
t+=DFS(i1,an); //增广轨
}
}
if(t==an) //当t==an时候,存在完美匹配
return 0;
return 1;
}
int main()
{
int i,j,k,pd;
while(scanf("%d%d",&n,&m)!=EOF)
{
gets(Map[1]+1);
memset(F,0,sizeof(F));
memset(Map,'X',sizeof(Map));
memset(Co,0,sizeof(Co));
for(i=1;i<=n;i++)
gets(Map[i]+1);
k=0; pd=0;
for(i=1;i<=n&&!pd;i++)
{
for(j=1;j<=m&&!pd;j++)
{
if(Map[i][j]=='.')
{
an=0; ++k; //
Color(i,j,k);
pd=Solve();
}
}
}
if(pd==1)
printf("1\n");
else
printf("2\n");
}
return 0;
}