考虑先对各点黑白染色,然后对于相邻的点连边建出二分图。
如果这个二分图有完全最大匹配(即每个点都匹配到了),那么先手必败,因为无论选那个点,后手只要向这个点匹配的另一个点走就行了。
如果是不完全最大匹配,那么先手必胜。
所以先手只要选到不一定在最大匹配中的点开始就一定赢,因为无论接下来后手走到哪里,先手只要跟着走到下一个匹配的点就行了。
所以只要先跑出一种最大匹配,然后从源点汇点分别 dfs 一遍就行了。
#include<bits/stdc++.h> #define edg(i,u) for(int i=head[u],v;v=edge[i].to,i;i=edge[i].nex) using namespace std;typedef long long ll;const int N=5e2+10,M=N*N,K=M*5;char a[N][N]; int n,m,k,s,t,head[M],kk=1,d[M],cur[M],tag[M],ans[M],vis[M];struct edges{int to,c,nex;}edge[K]; void add(int u,int v,int c){edge[++kk]={v,c,head[u]};head[u]=kk;edge[++kk]={u,0,head[v]};head[v]=kk;} int id(int x,int y){return (x-1)*m+y;} bool chk(int x,int y){return x>0&&y>0&&x<=n&&y<=m&&a[x][y]=='.';} bool bfs(){ queue<int>q;q.push(s);memset(d,-1,sizeof d);d[s]=0;cur[s]=head[s];for(int u;!q.empty();q.pop()){ u=q.front();edg(i,u)if(!~d[v]&&edge[i].c)q.push(v),d[v]=d[u]+1,cur[v]=head[v]; }return ~d[t]; } int dfs(int u,int lim=1e9){ if(u==t)return lim;int flow=0;for(int i=cur[u],v;v=edge[i].to,i&&flow<lim;i=edge[i].nex){ cur[u]=i;if(d[v]!=d[u]+1||!edge[i].c)continue;int f=dfs(v,min(lim-flow,edge[i].c)); if(!f)d[v]=-1;edge[i].c-=f;edge[i^1].c+=f;flow+=f; }return flow; } int dinic(){int maxflow=0;for(;bfs();)maxflow+=dfs(s);return maxflow;} void get(int u,int t){if(vis[u])return;vis[u]=1;if(tag[u]+t==2)ans[u]=1;edg(i,u)if(edge[i].c==t)get(v,t);} int main(){ cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i]+1;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)k+=a[i][j]=='.'&&(tag[id(i,j)]=((i+j)&1)+1); for(int i=1;i<=n;i++)for(int j=1;j<m;j++)if(a[i][j]=='.'&&a[i][j+1]=='.')(i+j)&1?add(id(i,j+1),id(i,j),1):add(id(i,j),id(i,j+1),1); for(int i=1;i<n;i++)for(int j=1;j<=m;j++)if(a[i][j]=='.'&&a[i+1][j]=='.')(i+j)&1?add(id(i+1,j),id(i,j),1):add(id(i,j),id(i+1,j),1); s=0;t=n*m+1;for(int i=1;i<t;i++)if(tag[i]==1)add(s,i,1);else if(tag[i]==2)add(i,t,1); if(dinic()*2==k)return puts("LOSE"),0;puts("WIN");get(s,1);memset(vis,0,sizeof vis); get(t,0);for(int i=1;i<t;i++)if(tag[i]&&ans[i])printf("%d %d\n",(i-1)/m+1,(i-1)%m+1);return 0; }