• CF919F


    题意:

    Alice和Bob玩游戏,每人各有8张牌,牌的大小在0~4之间

    每次操作,先手可以选择自己一张牌和对方一张牌求和后%5,将新的牌替代自己拿出的那张牌,以此类推,直到有一个人手中的牌全部是0,则这个人获胜

    但选牌时不能选择已经为0的牌进行操作

    现给定初始状态下两人的手牌以及先后手,求是否存在有人必胜

    分析:

    很显然是个博弈问题,对这种问题搜索是非常好用的。

    我们只需考虑一下设计状态

    很显然,一个人手牌的顺序对结果是没有任何影响的,所以状态数其实并不多

    那么我们不妨把所有状态设成手牌大小单调不降的。

    然后用排列组合计算一下,得一个人手牌总方案数为495(这个有很多算法,网上常见的算法比较简单(隔板法),但如果不熟悉隔板法(比如我),就使用了诡异的组合法:

    (分类讨论:

    ①:假设8张手牌的值相等,那么只会有C(5,1)种方案

    ②:假设8张手牌种出现了两种值,那么首先有C(5,2)种方法,同时考虑每种值出现的次数,发现有7种组合(1+7,2+6,3+5,4+4,5+3,6+2,7+1),所以这里的贡献是7*C(5,2)

    ③:假设8张手牌出现了3种值,那么首先有C(5,3)种方法,那么假设将这三个值放在前三位,剩下5个位置可以递归成①,②和③来处理...

    以此类推,最后将方案数累加,可以得出结果是495

    (天知道为什么我要用这么复杂的方法))

    那么,两个人的所有状态就是495^2,也是可以接受的

    接下来,两个状态之间会有相互的转移关系(先手的操作会把一种状态转变成另一种状态),那么我们对所有状态重新编号(这里我使用hash+map来实现),然后枚举所有的转移方案

    如果状态i可以转移至状态j,那么由J向I建一条边!(反向建边)

    然后,我们枚举所有状态,一定有一些状态是还没开始就结束(即一定先手必胜或先手必败的),那这些状态就是初始状态,直接推进队列里然后bfs,处理出剩下状态的情况,这也是反向建边的目的

    博弈搜索的原则:如果一个状态的后继状态中存在先手必败的状态,则这个状态为先手必胜,但如果所有后继状态都是先手必胜,那么这个状态就是先手必败的,但如果这个状态无法入队,则这个状态就是平局

    这样就完事了,预处理出所有状态的胜负手,然后直接输出答案即可

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <map> 
    #define seed 13131
    #define ull unsigned long long
    using namespace std;
    struct Edge
    {
        int next;
        int to;
    }edge[250005*64];
    struct node
    {
        int a[9];
        int b[9];
        ull hh;
        int typ;
    }sit[250005];
    int x[9];
    int temp[9];
    int temp2[9];
    int tempsit[250005][9];
    int head[250005];
    int ta[9],tb[9];
    int inr[250005];
    int cnt=1;
    int tot=0;
    int cct=0;
    map <ull,int> M,nnum,used[250005];
    queue <int> Q;
    void init()
    {
        memset(head,-1,sizeof(head));
        cnt=1;
    }
    void add(int l,int r)
    {
        edge[cnt].next=head[l];
        edge[cnt].to=r;
        head[l]=cnt++;
    }
    void dfs(int dep)
    {
        if(dep==9)
        {
            memcpy(temp,x,sizeof(x));
            sort(temp+1,temp+dep);
            ull has=1;
            for(int i=1;i<=8;i++)
            {
                has=has*seed+temp[i];
            }
            if(!M[has])
            {
                M[has]=1;
                tot++;
                memcpy(tempsit[tot],temp,sizeof(temp));
            }
            return;
        }
        for(int i=0;i<=4;i++)
        {
            x[dep]=i;
            dfs(dep+1);
        }
    }
    void judge()
    {
        for(int i=1;i<=tot*tot;i++)
        {
            bool flag=0;
            for(int j=1;j<=8;j++)
            {
                if(sit[i].a[j]!=0)
                {
                    flag=1;
                    break;
                }
            }
            if(!flag)
            {
                sit[i].typ=1;
                Q.push(i);
                continue;
            }
            flag=0;
            for(int j=1;j<=8;j++)
            {
                if(sit[i].b[j]!=0)
                {
                    flag=1;
                    break;
                }
            }
            if(!flag)
            {
                sit[i].typ=2;
                Q.push(i);
                continue;
            }
        }
    }
    void make_sit()
    {
        for(int i=1;i<=tot;i++)
        {
            for(int j=1;j<=tot;j++)
            {
                memcpy(sit[(i-1)*tot+j].b,tempsit[j],sizeof(sit[j].a));
                memcpy(sit[(i-1)*tot+j].a,tempsit[i],sizeof(sit[i].a));
                ull has=1;
                for(int k=1;k<=8;k++)
                {
                    has=has*seed+sit[(i-1)*tot+j].a[k];
                }
                for(int k=1;k<=8;k++)
                {
                    has=has*seed+sit[(i-1)*tot+j].b[k];
                }
                nnum[has]=(i-1)*tot+j;
                sit[(i-1)*tot+j].hh=has;
            }
        }
    }
    void add_edge()
    {
        for(int i=1;i<=tot*tot;i++)
        {
            for(int j=1;j<=8;j++)
            {
                if(sit[i].a[j]==0)
                {
                    continue;
                }
                for(int k=1;k<=8;k++)
                {
                    if(sit[i].b[k]==0)
                    {
                        continue;
                    }
                    int t=(sit[i].a[j]+sit[i].b[k])%5;
                    memcpy(temp,sit[i].b,sizeof(temp));
                    memcpy(temp2,sit[i].a,sizeof(temp2));
                    temp2[j]=t;
                    ull has=1;
                    sort(temp+1,temp+9);
                    sort(temp2+1,temp2+9);
                    for(int p=1;p<=8;p++)
                    {
                        has=has*seed+temp[p];
                    }
                    for(int p=1;p<=8;p++)
                    {
                        has=has*seed+temp2[p];
                    }
                    if(used[i][has])
                    {
                        continue;
                    }
                    used[i][has]=1;
                    add(nnum[has],i);
                    inr[i]++;
                }
            }
        }
    }
    void bfs()
    {
        while(!Q.empty())
        {
            int u=Q.front();      
            Q.pop();
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int to=edge[i].to;
                if(!inr[to])continue;
                if(sit[u].typ==2)
                {
                    sit[to].typ=1;
                    inr[to]=0;
                    Q.push(to);
                }else
                {
                    inr[to]--;
                    if(!inr[to]&&!sit[to].typ)
                    {
                        sit[to].typ=2;
                        Q.push(to);
                    }
                }
            }
        }
    }
    int main()
    {
        init();
        dfs(1);
        make_sit();
        judge();
        add_edge();
        bfs();
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int ty;
            scanf("%d",&ty);
            for(int i=1;i<=8;i++)
            {
                scanf("%d",&ta[i]);
            }
            for(int i=1;i<=8;i++)
            {
                scanf("%d",&tb[i]);
            }
            sort(ta+1,ta+9);
            sort(tb+1,tb+9);
            ull has=1;
            if(ty)
            {
                for(int i=1;i<=8;i++)
                {
                    has=has*seed+tb[i];
                }
                for(int i=1;i<=8;i++)
                {
                    has=has*seed+ta[i];
                }
                int t=nnum[has];
                if(sit[t].typ==0)
                {
                    printf("Deal
    ");
                    continue;
                }else if(sit[t].typ==1)
                {
                    printf("Bob
    ");
                    continue;
                }else
                {
                    printf("Alice
    ");
                    continue;
                }
            }else
            {
                for(int i=1;i<=8;i++)
                {
                    has=has*seed+ta[i];
                }
                for(int i=1;i<=8;i++)
                {
                    has=has*seed+tb[i];
                }
                int t=nnum[has];
                if(sit[t].typ==0)
                {
                    printf("Deal
    ");
                    continue;
                }else if(sit[t].typ==1)
                {
                    printf("Alice
    ");
                    continue;
                }else
                {
                    printf("Bob
    ");
                    continue;
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    《结对-航空购票系统-测试过程》
    《结对-航空购票系统-开发过程》
    课后作业-阅读任务-阅读提问-2
    《1005-构建之法:现代软件工程-阅读笔记》
    《团队-记事本程序-代码设计规范》
    Python作业:jieba库
    Python第四周作业:青蛙跳台阶、欧式距离、验证码校验、大小写互换、凯撒加密、身份证号处理
    Python汉诺塔问题
    第四周(1):利用Python计算π的值,并显示进度条
    Python第二周(1):凯撒密码B,括号配对测试,字符串反码,计算矩形面积,快乐的数字
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9849085.html
Copyright © 2020-2023  润新知