题意:

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[*];
struct node
{
int a[];
int b[];
ull hh;
int typ;
}sit[];
int x[];
int temp[];
int temp2[];
int tempsit[][];
int head[];
int ta[],tb[];
int inr[];
int cnt=;
int tot=;
int cct=;
map <ull,int> M,nnum,used[];
queue <int> Q;
void init()
{
memset(head,-,sizeof(head));
cnt=;
}
void add(int l,int r)
{
edge[cnt].next=head[l];
edge[cnt].to=r;
head[l]=cnt++;
}
void dfs(int dep)
{
if(dep==)
{
memcpy(temp,x,sizeof(x));
sort(temp+,temp+dep);
ull has=;
for(int i=;i<=;i++)
{
has=has*seed+temp[i];
}
if(!M[has])
{
M[has]=;
tot++;
memcpy(tempsit[tot],temp,sizeof(temp));
}
return;
}
for(int i=;i<=;i++)
{
x[dep]=i;
dfs(dep+);
}
}
void judge()
{
for(int i=;i<=tot*tot;i++)
{
bool flag=;
for(int j=;j<=;j++)
{
if(sit[i].a[j]!=)
{
flag=;
break;
}
}
if(!flag)
{
sit[i].typ=;
Q.push(i);
continue;
}
flag=;
for(int j=;j<=;j++)
{
if(sit[i].b[j]!=)
{
flag=;
break;
}
}
if(!flag)
{
sit[i].typ=;
Q.push(i);
continue;
}
}
}
void make_sit()
{
for(int i=;i<=tot;i++)
{
for(int j=;j<=tot;j++)
{
memcpy(sit[(i-)*tot+j].b,tempsit[j],sizeof(sit[j].a));
memcpy(sit[(i-)*tot+j].a,tempsit[i],sizeof(sit[i].a));
ull has=;
for(int k=;k<=;k++)
{
has=has*seed+sit[(i-)*tot+j].a[k];
}
for(int k=;k<=;k++)
{
has=has*seed+sit[(i-)*tot+j].b[k];
}
nnum[has]=(i-)*tot+j;
sit[(i-)*tot+j].hh=has;
}
}
}
void add_edge()
{
for(int i=;i<=tot*tot;i++)
{
for(int j=;j<=;j++)
{
if(sit[i].a[j]==)
{
continue;
}
for(int k=;k<=;k++)
{
if(sit[i].b[k]==)
{
continue;
}
int t=(sit[i].a[j]+sit[i].b[k])%;
memcpy(temp,sit[i].b,sizeof(temp));
memcpy(temp2,sit[i].a,sizeof(temp2));
temp2[j]=t;
ull has=;
sort(temp+,temp+);
sort(temp2+,temp2+);
for(int p=;p<=;p++)
{
has=has*seed+temp[p];
}
for(int p=;p<=;p++)
{
has=has*seed+temp2[p];
}
if(used[i][has])
{
continue;
}
used[i][has]=;
add(nnum[has],i);
inr[i]++;
}
}
}
}
void bfs()
{
while(!Q.empty())
{
int u=Q.front();
Q.pop();
for(int i=head[u];i!=-;i=edge[i].next)
{
int to=edge[i].to;
if(!inr[to])continue;
if(sit[u].typ==)
{
sit[to].typ=;
inr[to]=;
Q.push(to);
}else
{
inr[to]--;
if(!inr[to]&&!sit[to].typ)
{
sit[to].typ=;
Q.push(to);
}
}
}
}
}
int main()
{
init();
dfs();
make_sit();
judge();
add_edge();
bfs();
int T;
scanf("%d",&T);
while(T--)
{
int ty;
scanf("%d",&ty);
for(int i=;i<=;i++)
{
scanf("%d",&ta[i]);
}
for(int i=;i<=;i++)
{
scanf("%d",&tb[i]);
}
sort(ta+,ta+);
sort(tb+,tb+);
ull has=;
if(ty)
{
for(int i=;i<=;i++)
{
has=has*seed+tb[i];
}
for(int i=;i<=;i++)
{
has=has*seed+ta[i];
}
int t=nnum[has];
if(sit[t].typ==)
{
printf("Deal\n");
continue;
}else if(sit[t].typ==)
{
printf("Bob\n");
continue;
}else
{
printf("Alice\n");
continue;
}
}else
{
for(int i=;i<=;i++)
{
has=has*seed+ta[i];
}
for(int i=;i<=;i++)
{
has=has*seed+tb[i];
}
int t=nnum[has];
if(sit[t].typ==)
{
printf("Deal\n");
continue;
}else if(sit[t].typ==)
{
printf("Alice\n");
continue;
}else
{
printf("Bob\n");
continue;
}
}
}
return ;
}

CF919F的更多相关文章

  1. CF919F A Game With Numbers

    题目:(luogu翻译错的很多) Alice和Bob玩游戏,每人有8张牌,牌的值为0~4.每一轮当前玩家选择自己的牌A和对手的牌B,然后将A的值变为( A + B )%5,其中A和B都不是0. 当一个 ...

随机推荐

  1. Spring Boot Endpoint

    Spring Boot 的 Endpoints 带着强烈的 DevOps 色彩, “you build it, you run it” ,开发不仅要关心如何实现功能,还需要关心服务在线上运行的状态,如 ...

  2. 高程小tips

    1.DOM操作往往是JS程序中开销最大的部分,应尽量减少DOM操作.-P285  P297例子 2.元素的classList属性: 元素的classLis即该元素的class的值的集合,是一个列表(数 ...

  3. python - zipfile模块

    import zipfile # f=zipfile.ZipFile(filename, mode="r", compression=ZIP_STORED, allowZip64= ...

  4. SpringMVC中JSONP的基本使用

    @RequestMapping("/check/{param}/{type}") @ResponseBody public Object checkData(@PathVariab ...

  5. Django中session的基础了解

    基于cookie做用户验证时:敏感信息不适合放在cookie中 session依赖cookie session原理 cookie是保存在用户浏览器端的键值对 session是保存在服务器端的键值对 s ...

  6. [转] Torch中实现mini-batch RNN

    工作中需要把一个SGD的LSTM改造成mini-batch的LSTM, 两篇比较有用的博文,转载mark https://zhuanlan.zhihu.com/p/34418001 http://ww ...

  7. delphi 的插件机制与自动更新

    delphi 的插件机制与自动更新 : 1.https://download.csdn.net/download/cxp_2008/2226978   参考 2.https://download.cs ...

  8. 设计模式C++学习笔记之六(Facade门面模式)

      Facade门面模式,也是比较常用的一种模式,基本上所有软件系统中都会用到. GOF 在<设计模式>一书中给出如下定义:为子系统中的一组接口提供一个一致的界面, Facade 模式定义 ...

  9. 通信——基于Xmpp协议实现的聊天室

    前段时间写了个自定义通信协议的聊天室(即用\r\n标记字符串,作为一句话),总感觉自己弄的那个协议实现虽然简单,但是拓展性就太差了,只适合于发送聊天的内容,难以包含更多的信息.基于上述几点,于是就开始 ...

  10. MySQL查询语句练习题,测试基本够用了

    Sutdent表的定义 字段名 字段描述 数据类型 主键 外键 非空 唯一 自增 Id 学号 INT(10) 是 否 是 是 是 Name 姓名 VARCHAR(20) 否 否 是 否 否 Sex 性 ...