BZOJ 1443: [JSOI2009]游戏Game

1443: [JSOI2009]游戏Game

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1077  Solved: 484
[Submit][Status][Discuss]

Description

Input

输入数据首先输入两个整数N,M,表示了迷宫的边长。 接下来N行,每行M个字符,描述了迷宫。

Output

若小AA能够赢得游戏,则输出一行"WIN",然后输出所有可以赢得游戏的起始位置,按行优先顺序输出 每行一个,否则输出一行"LOSE"(不包含引号)。

Sample Input

3 3
.##
...
#.#

Sample Output

WIN
2 3
3 2

HINT

 

对于100%的数据,有1≤n,m≤100。 对于30%的数据,有1≤n,m≤5。

 

Source

分析:

这是一个网格图,然后每个状态只能向相邻的状态转移,并且输赢和路径长度的奇偶性有关系,所以考虑黑白染色,也就是状态只能向不同的颜色转移,那么就是一个二分图...

如果二分图求完最大匹配之后不存在非匹配点,那么一定不存在必胜策略,因为我们求完最大匹配之后,一定不存在增广路,只存在交错路,对方从匹配点出发,最后一定可以找到一条匹配边作为结束,所以先手必胜...

那么也就是说,从一个非匹配点出发,一定是一个后手必胜的策略,但是非匹配点并不是全部答案,因为并不是值存在一组最大匹配,所以从每个非匹配点出发,寻找交错路,然后访问到的和非匹配点处于同一集合的点都是答案...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=200+5,maxm=20000+5;

int n,m,cnt,tot,f[maxn][maxn],hd[maxm],to[maxm<<1],nxt[maxm<<1];
int pre[maxm],vis[maxm],co[maxm],ans[maxm];
int mv[2][2]={0,1,1,0};

char mp[maxn][maxn];

inline void add(int x,int y){
	to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
}

inline bool dfs(int x){
	for(int i=hd[x];i!=-1;i=nxt[i])
		if(!vis[to[i]]){
			vis[to[i]]=1;
			if(pre[to[i]]==-1||dfs(pre[to[i]])){
				return pre[to[i]]=x,true;
			}
		}
	return false;
}

inline void find(int x){
	if(ans[x])
		return;
	ans[x]=1;
	for(int i=hd[x];i!=-1;i=nxt[i])
		if(pre[to[i]]!=-1)
			find(pre[to[i]]);
}

signed main(void){
	scanf("%d%d",&n,&m);
	memset(hd,-1,sizeof(hd));
	memset(pre,-1,sizeof(pre));
	for(int i=1;i<=n;i++)
		scanf("%s",mp[i]+1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(mp[i][j]=='.')
				f[i][j]=++tot,co[f[i][j]]=(i^j)&1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(mp[i][j]=='.')	
				for(int k=0;k<2;k++){
					int x=i+mv[k][0],y=j+mv[k][1];
					if(f[x][y])
						add(f[i][j],f[x][y]),add(f[x][y],f[i][j]);
				}
	for(int i=1;i<=tot;i++)
		if(co[i])
			memset(vis,0,sizeof(vis)),cnt+=dfs(i);
	if(cnt*2==tot){
		puts("LOSE");
		return 0;
	}
	puts("WIN");
	for(int i=1;i<=tot;i++)
		if(pre[i]!=-1)
			pre[pre[i]]=i;
	for(int i=1;i<=tot;i++)
		if(pre[i]==-1)
			find(i);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(ans[f[i][j]])
				printf("%d %d\n",i,j);
	return 0;
}

  


By NeighThorn

posted @ 2017-03-06 13:16  NeighThorn  阅读(470)  评论(0编辑  收藏  举报