• [NOI2011]兔兔与蛋蛋游戏


    传送门

    直接博弈论dfs可以得到75分(然鹅我博弈论学的很pie)

    #include<bits/stdc++.h>
    #define LL long long
    #define INF 10000
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }  
    char s[45];
    int lr[]={0,0,1,-1},ud[]={1,-1,0,0},ans[1003],tu[43][43],sg[43];
    int X,Y,tot=0,n,m;
    int dfs(int x,int y,int op)
    {
        for(int i=0;i<4;++i)
        {
            int xx=x+ud[i],yy=y+lr[i];
            if(xx<1||xx>n||yy<1||yy>m||tu[xx][yy]!=op)continue;
            swap(tu[xx][yy],tu[x][y]);
            if(!dfs(xx,yy,op^1)){swap(tu[xx][yy],tu[x][y]);return 1;}//往下递归得到每一个局面,判断其为必胜还是必败 
            swap(tu[xx][yy],tu[x][y]);
        }
        return 0; 
    }
    int main()
    {
    //    freopen("game.in","r",stdin);
    //    freopen("game.out","w",stdout);
        n=read(),m=read();
        for(int i=1;i<=n;++i)
        {
            scanf("%s",s+1);
            for(int j=1;j<=m;++j)
            {
                if(s[j]=='X')tu[i][j]=1;//黑棋 
                else if(s[j]=='.')tu[i][j]=2,X=i,Y=j;//空格 
            } 
        }
        int op=read();
        for(int i=1;i<=op;++i)
        {
            int x=read(),y=read();
            sg[i]=dfs(X,Y,0);
            swap(tu[x][y],tu[X][Y]);
            X=x;Y=y;
            if(sg[i]&&dfs(X,Y,1))ans[++tot]=i;//走之前兔兔是必胜态,走之后蛋蛋是必胜态 
            x=read(),y=read();
            swap(tu[x][y],tu[X][Y]);
            X=x;Y=y;
        }
        printf("%d
    ",tot);
        for(int i=1;i<=tot;++i)
          printf("%d
    ",ans[i]);    
    } 
    /*
    */
    75分

    然后正解是二分图。。。哇这谁想得到是二分图

    让我们认真分析一下:

    每一次顺序移动白格黑格,当最后无法移动停止,且每一个格子只会走过一次(感性感知)相当于是黑白交替格子染色—>想到二分图。

    与其说是每次交换空格和其他黑白格,不如说是空格在黑白格上走。(第一步在空格本身上)

    我们可以把第一步认为是黑格,然后交替走黑白格,如果最后走到黑格,说明兔兔输了(兔兔移动白格)。

    然后二分图匹配保证了最后走到的一定是白格,因为从黑格出发(要求每一条路都是奇数步)

    走格子相当于是在增广路上走,如果当前x,y一定在最大匹配上(在增广路上而且没有其他的增广路可以替代它了),说明现在是必胜态。

    然后对于每一步进行判断,如果兔兔和蛋蛋的第i步都是必胜态,说明兔兔在走第i步之前是必胜态,走了第i步后蛋蛋就是必胜态了。

    满足题目要求,累计答案。

    #include<bits/stdc++.h>
    #define N 43
    #define LL long long
    #define INF 10000
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }  
    struct EDGE{
        int nextt,to;
    }w[N*N*4];
    char s[N];
    int lr[]={0,0,1,-1},ud[]={1,-1,0,0},ans[1003],tu[N][N],head[N*N],ord[N][N],vis[N*N],match[N*N],ban[N*N],win[1003];
    int X,Y,tot=0,n,m,ndnum=0,res=0,timer=0;
    void add(int a,int b)
    {
        tot++;
        w[tot].nextt=head[a];
        w[tot].to=b;
        head[a]=tot;
    }
    void jian_tu()//建二分图 
    {
        for(int i=1;i<=n;++i)
          for(int j=1;j<=m;++j)
          {
              if(!tu[i][j])continue;
              for(int k=0;k<4;++k)
            {
                int xx=i+ud[k],yy=j+lr[k];
                if(xx<1||xx>n||yy<1||yy>m||tu[xx][yy])continue;
                add(ord[i][j],ord[xx][yy]);
                add(ord[xx][yy],ord[i][j]);
            }
          }
    }
    int dfs(int x)
    {
        if(vis[x]==timer||ban[x])return 0;
        vis[x]=timer;
        for(int i=head[x];i;i=w[i].nextt)
        {
            int v=w[i].to;
            if(ban[v])continue;
            if(!match[v]||dfs(match[v]))
            {
                match[v]=x;match[x]=v;
                return 1;
            }
        }
        return 0;
    }
    int main()
    {
    //    freopen("game.in","r",stdin);
    //    freopen("game.out","w",stdout);
        n=read(),m=read();
        for(int i=1;i<=n;++i)
        {
            scanf("%s",s+1);
            for(int j=1;j<=m;++j)
            {
                ord[i][j]=++ndnum; 
                if(s[j]=='X')tu[i][j]=1;//黑棋 
                else if(s[j]=='.')tu[i][j]=2,X=i,Y=j;//空格 
            } 
        }
        jian_tu();
        for(int i=1;i<=n;++i)
          for(int j=1;j<=m;++j)
            if(tu[i][j])timer++,dfs(ord[i][j]);
        int op=read();
        for(int i=1;i<=op*2;++i)
        {
            int id=ord[X][Y];
            ban[id]=1;
            if(match[id])
            {
                int v=match[id];
                match[id]=match[v]=0;
                ++timer;
                win[i]=(!dfs(v));//在增广路上且不可代替 
            }
            X=read();Y=read();
        }
        for(int i=1;i<=op;++i)
          if(win[2*i-1]&&win[2*i])ans[++res]=i;
        printf("%d
    ",res);
        for(int i=1;i<=res;++i)
          printf("%d
    ",ans[i]);    
    } 
    二分图AC
  • 相关阅读:
    常用的CSS命名规则 (web标准化设计)
    有哪些概率论和数理统计的深入教材可以推荐?
    CV2X国内现状分析
    隐私计算,新能源汽车“安全上路”的“救命稻草”?
    2022年中国车联网行业全景图谱
    2022年十大AI预测:气候独角兽涌现、中美竞争加剧
    OSEK/VDX介绍
    Adaptive Autosar
    基于我国商密算法的车联网5GV2X通信安全可信体系
    行研篇 | 汽车域控制器研究
  • 原文地址:https://www.cnblogs.com/yyys-/p/11514768.html
Copyright © 2020-2023  润新知