码迷,mamicode.com
首页 > 其他好文 > 详细

CF919F

时间:2018-10-25 14:12:35      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:ret   span   stream   emc   操作   math   cst   scan   好用   

题意:

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\n");
                continue;
            }else if(sit[t].typ==1)
            {
                printf("Bob\n");
                continue;
            }else
            {
                printf("Alice\n");
                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\n");
                continue;
            }else if(sit[t].typ==1)
            {
                printf("Alice\n");
                continue;
            }else
            {
                printf("Bob\n");
                continue;
            }
        }
    }
    return 0;
}

 

CF919F

标签:ret   span   stream   emc   操作   math   cst   scan   好用   

原文地址:https://www.cnblogs.com/zhangleo/p/9849085.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!