BZOJ:1443: [JSOI2009]游戏Game
原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1443
反正不看题解我是完全想不出系列……
先把棋盘黑白染色,也就是同一对角线上颜色相同,使得一个格子上下左右都不同色。
然后我们会发现,某一个人所走的全部格子颜色都是相同的。
把黑白格子当作点提取出来,放在两边,就变成了二分图,游戏的全过程变得像匈牙利算法的增广。
这提示我们也许跟二分图匹配有关。
如果一个点必定在最大匹配中,而一开始棋子放在了这里小YY只要沿着匹配边走小AA就gg了。
注意这里说的是必定在最大匹配中,所以并不用担心出现走到某个非匹配点后小YY无路可走的情形,此时可以通过伪增广保持最大匹配数不变而使起点不在匹配点中。
对于匈牙利算法,可以通过类似的伪增广找出所有不一定在最大匹配中的点。
对于网络流,未被割掉与源汇相邻的边的点肯定是答案,至于其他可以是答案的点,可以通过走反向边(与匈牙利类似的交错路径)来实现到达汇点或从源点出发可达。也就是在残余网络中源点可达且在二分图靠近源点一侧的点,可到达汇点且在二分图靠近汇点一侧的点(没这俩限制就gg了)都是答案点。(注意建图时建单向边,即反向边初始流量为0)
#include<cstdio> #include<algorithm> #define MN 110001 using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } const int fx[4]={1,-1,0,0},fy[4]={0,0,1,-1}; struct na{int y,f,ne;}b[MN]; int n,m,l[MN],be[101][101],nm=0,S,T,num=1,d[MN],g[MN],c[MN],mmh=0; bool bo[MN],O_O[MN]; char s[101][101]; inline void add(int x,int y,int f){b[++num].y=y;b[num].f=f;b[num].ne=l[x];l[x]=num;} inline void in(int x,int y,int f){add(x,y,f);add(y,x,0);} int sap(int x,int f){ if (x==T) return f; int h=0,q; for (int i=d[x];i;i=b[i].ne) if (b[i].f&&g[x]==g[b[i].y]+1){ q=sap(b[i].y,min(f-h,b[i].f)); b[i].f-=q;b[i^1].f+=q;h+=q;d[x]=l[x]; if (h==f) return h; if (g[S]==nm) return h; } if (!--c[g[x]]) g[S]=nm;++c[++g[x]];d[x]=l[x]; return h; } void dfs(int x,bool B){ if (bo[x]) return; bo[x]=1;O_O[x]^=B; for (int i=l[x];i;i=b[i].ne) if (b[i].f==B) dfs(b[i].y,B); } int main(){ register int i,j,k; n=read();m=read(); for (i=1;i<=n;i++) scanf("%s",s[i]+1); for (i=1;i<=n;i++) for (j=1;j<=m;j++) if (s[i][j]=='.') be[i][j]=++nm; S=++nm;T=++nm; for (i=1;i<=n;i++) for (j=1;j<=m;j++) if (s[i][j]=='.') for (k=0;k<4;k++) if (s[i+fx[k]][j+fy[k]]=='.') if ((i+j)&1) in(be[i+fx[k]][j+fy[k]],be[i][j],1);else in(be[i][j],be[i+fx[k]][j+fy[k]],1); for (i=1;i<=n;i++) for (j=1;j<=m;j++) if (s[i][j]=='.') if (mmh++,O_O[be[i][j]]=((i+j)&1)) in(be[i][j],T,1);else in(S,be[i][j],1); for (;g[S]<nm;mmh-=2*sap(S,1e9)); if (!mmh) return puts("LOSE"),0; puts("WIN"); dfs(S,1);dfs(T,0); for (i=1;i<=n;i++) for (j=1;j<=m;j++) if (s[i][j]=='.'&&bo[be[i][j]]&&O_O[be[i][j]]) printf("%d %d\n",i,j); }