Description
Input
输入数据首先输入两个整数N,M,表示了迷宫的边长。 接下来N行,每行M个字符,描述了迷宫。
Output
若小AA能够赢得游戏,则输出一行"WIN",然后输出所有可以赢得游戏的起始位置,按行优先顺序输出 每行一个,否则输出一行"LOSE"(不包含引号)。
Sample Input
3 3
.##
...
#.#
.##
...
#.#
Sample Output
WIN
2 3
3 2
2 3
3 2
HINT
对于100%的数据,有1≤n,m≤100。 对于30%的数据,有1≤n,m≤5。
题解:
可以看出来是二分图博弈的模型。
对图黑白染色之后判断先手是否必胜跑一遍匈牙利算法看一下是否存在完备匹配即可。
如果存在一定是先手必败。
对于第二问,我们可以记录一下左边没有匹配的点。
从这些点开始dfs,从左到右走非匹配边,从右向左走匹配边。
这样dfs到的左边的点就是答案。
然后把二分图左右两边倒过来再做一遍即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 510
using namespace std;
int t1,t2,pos[N][N],x[4]={1,0,-1,0},y[4]={0,1,0,-1},bl[N*N];
int n,m,cnt,point[N*N],next[N*N],num,to[N*N];
bool f[N*N],vis[2][N*N],p[N*N];
char s[N][N];
void add(int x,int y){next[++cnt]=point[x];point[x]=cnt;to[cnt]=y;}
bool find(int x){
for (int i=point[x];i;i=next[i])
if (!f[to[i]]){
f[to[i]]=1;
if (!bl[to[i]]||find(bl[to[i]])){bl[to[i]]=x;return true;}
}
return false;
}
void dfs(int x,bool vis[]){
vis[x]=1;
for (int i=point[x];i;i=next[i])
if (!vis[bl[to[i]]])dfs(bl[to[i]],vis);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (s[i][j]=='.') pos[i][j]=++(i+j&1?t1:t2);
for(int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (s[i][j]=='.'&&(i+j&1))
for (int k=0;k<4;k++){
int px=i+x[k],py=j+y[k];
if (px<=0||py<=0||px>n||py>m||s[px][py]=='#') continue;
add(pos[i][j],pos[px][py]);
}
for (int i=1;i<=t1;i++){
memset(f,0,sizeof(f));
if (find(i)) num++;else p[i]=1;
}
if (num==t1&&num==t2){printf("LOSE\n");return 0;}
for (int i=1;i<=t1;i++) if (p[i]) dfs(i,vis[1]);
memset(point,0,sizeof(point));
memset(p,0,sizeof(p));
memset(bl,0,sizeof(bl));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (s[i][j]=='.'&&((i+j)%2==0)){
for (int k=0;k<4;k++){
int px=i+x[k],py=j+y[k];
if (px<=0||py<=0||px>n||py>m||s[px][py]=='#') continue;
add(pos[i][j],pos[px][py]);
}
}
for (int i=1;i<=t2;i++){
memset(f,0,sizeof(f));
if (!find(i)) p[i]=1;
}
for (int i=1;i<=t2;i++) if (p[i]) dfs(i,vis[0]);
printf("WIN\n");
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
if ((i+j&1)&&(vis[1][pos[i][j]]))printf("%d %d\n",i,j);
if (((i+j)%2==0)&&(vis[0][pos[i][j]])) printf("%d %d\n",i,j);
}
}