zoukankan      html  css  js  c++  java
  • 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
    ",i,j);
    }
    View Code
  • 相关阅读:
    YTU 2543: 数字整除
    YTU 2542: 弟弟的作业
    YTU 2541: 汽水瓶
    YTU 2535: C++复数运算符重载(+与<<)
    YTU 2530: 小勇玩lol
    YTU 2520: 小慧唱卡拉OK
    YTU 2517: 打倒魔王↖(^ω^)↗
    YTU 2516: 剪刀石头布
    reload、replace、href、assign、window.history.go(0)的区别
    js 数组排序sort方法
  • 原文地址:https://www.cnblogs.com/Enceladus/p/6687323.html
Copyright © 2011-2022 走看看