首页 > 代码库 > BZOJ:1443: [JSOI2009]游戏Game

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);
}
View Code

 

BZOJ:1443: [JSOI2009]游戏Game