题意:

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 源码分析 spring-core 篇

    先来看下 spring-core 的包结构 总共有6个模块,分别是 asm.cglib.core.lang.objenesis.util asm包: 用来操作字节码,动态生成类或者增强既有类的功能.主 ...

  2. Tip: JSP开发模式

    SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. JSP+JavaBean模式适合开发业务 ...

  3. ASP.NET - ADO.NET框架

    ADO.NET(ActiveX Data Objects) ADO.NET是一个COM组件库,用于在使用Microsoft技术的代码中访问数据库. SQL数据操作类 SqlConnection类(Sy ...

  4. 已安装nginx支持https配置 the "ssl" parameter requires ngx_http_ssl_module

    原文链接:https://blog.seosiwei.com/detail/28 nginx已安装,ssl模块未安装的解决方法: 如果需要在linux中编译自己的nginx服务器,请参照:https: ...

  5. iris数据集(鸢尾花)

    包含三个花的品种(Iris setosa(山鸢尾),Iris virginica(北美鸢尾),Iris versicolor(变色鸢尾)) 每个品种各50个样 每个样本四个特征参数(萼片长度和宽度.花 ...

  6. win10 python27pyhton36共存

    先前安装了python36 然后安装python27,安装步骤如下 1. 到官网下载https://www.python.org/downloads/windows/,我的是win10 64位,选择了 ...

  7. Visual Studio VS2010统计代码行数

    按CTRL+SHIFT+F (Find in files),勾上支持正则表达式,然后输入搜索内容: ^:b*[^:b#/]+.*$ 以上表达式的统计可做到:#开头和/开头或者空行都不计入代码量.如果需 ...

  8. WARN: Establishing SSL connection

    在我们使用连接MySQL数据库时会出现这样的提示: Tue Aug 29 13:24:29 CST 2017 WARN: Establishing SSL connection without ser ...

  9. 利用URLConnection http协议实现webservice接口功能(附HttpUtil.java)

    URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和 URL 之间的通信链接.程序可以通过URLConnection实例向该URL发送请求.读取U ...

  10. document.execCommand()的用法小记

    项目中遇到金额输入框限制只能输入数字,输入特殊字符或者字母汉字时间隔不到1秒内容就会自动清空.跟正则纠缠多年的我初次见到,很是神奇-.- 代码实现: <input type="text ...