[NOI2011Day2 兔兔与蛋蛋游戏]

[关键字]:二分图

[题目大意]:http://192.168.1.9:8586/JudgeOnline/showproblem?problem_id=1672

[分析]:这是一道二分图匹配的问题,先说说我的思路:每次与空格的交换只能是黑白交替,所以可以看成空格在黑格和白格间交替的走。于是棋盘就变成了一个二分图,黑格向他周围的白格连边,白格同理,空格一开始为黑色然后黑白交替变色,每次走一步都对交换的两个点重新连边。至于判断必胜或必败,如果空格沿着当前二分图不回头的走到了黑格,则白胜否则黑胜。然后我就纠结了,这里面有许多思路不清晰的地方也有许多很难完成的地方复杂度也没有保证。然后看了题解,发现自己其实已经离AC思路很近了,只要把原始思路的本质发掘出来就行了。原始思路中第一步建图之所以导致后来需要不停的更改就是因为有些点是不可能走到的(因为只能黑白交替走),而这些点可以通过一开始一遍BFS处理出来。第二部找必胜态,其实就是判断二分图最大匹配是否包含当前起点(就是当前空格所在点),如果在此时的先手赢否则后手赢。原因很简单,如果起点在最大匹配上先手走一步到后手的颜色的节点上,就会逼迫后手走到另一个匹配对的先手所在的颜色的节点上去,这样一定会导致后手处在一个自己颜色的节点上无路可走,正好是上面原始思路中的判断必胜必败的实质。最后终结一下算法步骤:

1、BFS找出所有可以走到的节点,并黑白染色建立二分图。

2、对于每一步更新起点位置,判断此时是否符合犯错误的要求(蛋蛋走前先手胜走后还是先手胜)。

3、判断是每次都用匈牙利算法判断起点是否在二分图上。

看来还是自己的只是掌握不熟练,思维深度还不够,真是悲剧!

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};

struct node
{
int x,y;
}q[2000];
int n,m,K,sx,sy,ans;
int f[2500],a[100][100],b[100][100],g[2000][2000],match[2500];
char ch;
bool c[2500],v[100][100],vis[2500];

bool dfs(int u)
{
for (int i=1;i<=g[u][0];i++)
{
int v=g[u][i];
if (!vis[v] && c[v])
{
vis[v]=1;
if (match[v]==-1 || dfs(match[v]))
{
match[u]=v;
match[v]=u;
return 1;
}
}
}
return 0;
}

bool Win()
{
//printf("%d %d\n",n,m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
g[(i-1)*m+j][0]=0;
for (int k=0;k<4;k++)
{
int xx=dx[k]+i,yy=dy[k]+j;
if (1<=xx && xx<=n && 1<=yy && yy<=m && c[(i-1)*m+j] && c[(xx-1)*m+yy] && (xx+yy)&1)
g[(i-1)*m+j][++g[(i-1)*m+j][0]]=(xx-1)*m+yy;
}
}
int sum=0;
c[(sx-1)*m+sy]=0;
memset(match,-1,sizeof(match));
for (int i=1;i<=n*m;i++)
if (c[i])
{
memset(vis,0,sizeof(vis));
if (dfs(i)) sum++;
}
memset(match,-1,sizeof(match));
c[(sx-1)*m+sy]=1;
for (int i=1;i<=n*m;i++)
if (c[i])
{
memset(vis,0,sizeof(vis));
if (dfs(i)) sum--;
}
if (!sum) return 0; else return 1;
}

int main()
{
scanf("%d%d\n",&n,&m);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
scanf("%c",&ch);
if (ch=='X') a[i][j]=1;
if (ch=='O') a[i][j]=-1;
if (ch=='.') sx=i,sy=j;
//printf("%c\n",map[i][j]);
}
scanf("\n");
}
int head=1,tail=1;
memset(v,0,sizeof(v));
q[1].x=sx,q[1].y=sy,v[sx][sy]=1,b[sx][sy]=0;
while (head<=tail)
{
for (int i=0;i<4;i++)
{
int xx=dx[i]+q[head].x,yy=dy[i]+q[head].y;
if (1<=xx && xx<=n && 1<=yy && yy<=m && !v[xx][yy])
{
if (a[q[head].x][q[head].y]==0) b[xx][yy]=-1;
else b[xx][yy]=-b[q[head].x][q[head].y];
q[++tail].x=xx,q[tail].y=yy,v[xx][yy]=1;
}
}
head++;
}
//printf("%d %d\n",n,m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (a[i][j]!=b[i][j]) c[(i-1)*m+j]=0; else c[(i-1)*m+j]=1;
scanf("%d",&K);
for (int i=1;i<=K;i++)
{
bool win=Win();
int x,y;
scanf("%d%d",&x,&y);
c[(sx-1)*m+sy]=0;
sx=x,sy=y;
if (win && Win()) f[++ans]=i;
//printf("%d %d\n",x,y);
scanf("%d%d",&x,&y);
c[(sx-1)*m+sy]=0;
sx=x,sy=y;
}
printf("%d\n",ans);
for (int i=1;i<=ans;i++) printf("%d\n",f[i]);
system("pause");
return 0;
}


 

你可能感兴趣的:(游戏)