• BZOJ:[JSOI2009]游戏Game【二分图匹配乱搞】


    题目大意:n*m的棋盘,其中有些区域是禁区,两个人在棋盘上进行博弈,后手选择棋子的初始位置,然后先后手轮流将棋子往上下左右移动,走过的区域不能再走,问能否有一个位置使得后手必胜

    Input

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

    Output

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

    Sample Input

    3 3
    .##
    ...
    #.#

    Sample Output

    2 3
    3 2

    HINT

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

    Source

    JSOI2009Day2

    完成二分图这章绝对有必要做的一题

    思路:如果没有禁区,那这题就沦为了这题:http://hi.baidu.com/lov_zyf/item/04fa260e7b3ba41acc34eaff  [中山市选2009]谁能赢呢?

    唔 分奇偶讨论就行,那有禁区怎么办?其实可以从上面那题收到启发,就是1*2的骨牌的覆盖问题,然后大白书二分图匹配那章那个经典的博弈也是解开这题的关键

    显然如果棋盘能完全被1*2骨牌覆盖,那么后手必输,因为先手总能移动到骨牌的另一端,如果不能被完全覆盖呢?只要将棋子放在没被覆盖的那点就行了,先手第一步一定移动到一个骨牌里去,先后手交换

    间二染色后,这个问题成了二分图匹配的问题,只要初始位置是一个未盖点,那么后手一定能沿着增光轨走下去,因此后手必胜

    那么判断出胜负后接下来问题就是哪些位置可能成为初始位置,基于上面的讨论这个点一定是可能成为未盖点的点(因为二分图的最大匹配可能有很多种样子,虽然匹配数相同)

    最直观的方法应该是:考虑一个点如果一定在最大匹配里(也就是不可能成为初始点)那么将这个点删除,其它边不变做一次匈牙利,看最大匹配数是否改变,但这是个显然超时的做法

    于是我考虑一个y部的点时,保留之前做过的最短路,把这点标记掉,如果之前和y部这个点匹配的点能继续增广,也就是在最大匹配保持不变的情况下,这个点能和新的点匹配,那这个y部的点就是可有可无的了,也就是可以成为未盖点

    ------------------------------------------------------------------------------------------------------------

    顺便做完后百度了下题解,发现做法真多!二分图那部边基本是相同的思路,考虑哪些点可能成为未盖点的时候有沿着增广轨DFS的,有网络流的,而且速度都比我快,果然还是too young

    #include <stdio.h>

    #include <iostream>

    #include<queue>

    #include <string.h>

    #include <algorithm>

    #define maxn 200000

    #define maxm 1000005

    #define inf 0x3f3f3f3f

    using namespace std;

    const int dx[10]={0,0,0,1,-1};

    const int dy[10]={0,1,-1,0,0};

    int next[maxn],head[maxn],now,point[maxn];

    int match[maxn],x[maxn],y[maxn],mat[maxn];

    bool visit[maxn],mark[maxn];

    char ch[200][200];

    void add(int x,int y)

    {

        next[++now]=head[x];

        head[x]=now;

        point[now]=y;

    }

    int dfs(int k)

    {

        for(int i=head[k];i;i=next[i])if(!visit[point[i]])

        {

            int u=point[i];

            visit[u]=1;

            if(dfs(match[u])||match[u]==-1)

            {

                match[u]=k;

                mat[k]=u;

                return 1;

            }

        }

        return 0;

    }

    int main()

    {

        int n,m,u=0,v=0,flag=0;

        scanf("%d%d",&n,&m);

        for(int i=1;i<=n;i++)scanf("%s",ch[i]+1);

        int fi=0;

        for(int i=1;i<=n;i++)

        {

            fi^=1;

            for(int j=fi+1;j<=m;j+=2)if(ch[i][j]=='.')

            {

                x[++u]=i*m+j;

                for(int k=1;k<=4;k++)

                {

                    int xx=i+dx[k],yy=j+dy[k];

                    if(ch[xx][yy]=='.')

                    {

                        add(i*m+j,xx*m+yy);

                        add(xx*m+yy,i*m+j);

                    }

                }

            }

        }

        fi=1;

        for(int i=1;i<=n;i++)

        {

            fi^=1;

            for(int j=fi+1;j<=m;j+=2)

                if(ch[i][j]=='.')y[++v]=i*m+j;

        }

        memset(match,-1,sizeof(match));

        for(int i=1;i<=u;i++)

        {

            memset(visit,0,sizeof(visit));

            if(!dfs(x[i]))

            {flag=1;mark[x[i]]=1;}

        }

        for(int i=1;i<=v;i++)

        {

            if(match[y[i]]==-1){mark[y[i]]=1;flag=1;}

            else

            {

                memset(visit,0,sizeof(visit));

                visit[y[i]]=1;

                if(dfs(match[y[i]]))

                {match[y[i]]=-1;mark[y[i]]=1;flag=1;}

            }

        }

        for(int i=1;i<=v;i++)

        {

            memset(visit,0,sizeof(visit));

            if(!dfs(y[i]))

            {flag=1;mark[y[i]]=1;}

        }

        for(int i=1;i<=u;i++)

        {

            if(match[x[i]]==-1){mark[x[i]]=1;flag=1;}

            else

            {

                memset(visit,0,sizeof(visit));

                visit[x[i]]=1;

                if(dfs(match[x[i]]))

                {match[x[i]]=-1;mark[x[i]]=1;flag=1;}

            }

        }

        if(flag==1)printf("WIN ");else{printf("LOSE ");return 0;}

        for(int i=1;i<=n;i++)

        {

            for(int j=1;j<=m;j++)

            {

                if(mark[i*m+j])printf("%d %d ",i,j);

            }

        }

        return 0;

    }

  • 相关阅读:
    一款React版本的excel插件(reactjexcel)
    如何评价微软的微服务构建框架Dapr?
    【优雅代码】深入浅出 妙用Javascript中apply、call、bind
    国内外最顶级的12大看板工具
    基于键盘钩子实现扫码枪输入
    中国有哪些比较出名的C#大佬。?
    一个数据驱动的高效 dotnet PDF 开源工具库
    Web前端:2022年最佳Javascript动画库
    分布式数据库的高可用性简史
    Vue项目首屏打开速度的优化
  • 原文地址:https://www.cnblogs.com/philippica/p/4091609.html
Copyright © 2020-2023  润新知