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[*];
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的更多相关文章
- CF919F A Game With Numbers
题目:(luogu翻译错的很多) Alice和Bob玩游戏,每人有8张牌,牌的值为0~4.每一轮当前玩家选择自己的牌A和对手的牌B,然后将A的值变为( A + B )%5,其中A和B都不是0. 当一个 ...
随机推荐
- javascript数据类型和常用内置对象(重要!)
数据类型:w3c undefind null string number boolean Array object 常用内置javascript对象: Array对象:Date对象:正则 ...
- Centos7 nginx提示错误 Access denied.
SELinux will cause this error on CentOS/RHEL 7+ by default :( CentOS/RHEL 7+ 系统默认会因为SELinux出现这个报错 To ...
- AutoML总结
原文:JxKing的博客 | JxKing Blog 前言 AutoML是指尽量不通过人来设定超参数,而是使用某种学习机制,来调节这些超参数.这些学习机制包括传统的贝叶斯优化,多臂老虎机(multi- ...
- linux 安装图行界面
centos6的环境中 代码:[root@ebs122 sysconfig]#yum groupinstall "Desktop" 使用 init 5命令进入图形化界面,如果成功的 ...
- glCleatDepth
opengl里面的深度缓存 在现实生活中,一个实心物体挡在另外一个实心物体的前面, 后面的那个物体有部分会被遮盖掉 那么opengl里面如何模拟这个情况呢? 每个物体的每个像素都有一个深度缓存的值( ...
- 高手进阶,终极内存技术指南——完整/进阶版 II (转)【转】
转自:https://blog.csdn.net/lightseed/article/details/4630170 SDRAM芯片的预充电与刷新操作 预充电 由于SDRAM的寻址具体独占性,所以在进 ...
- linux虚拟机网络服务问题
这里说一下我遇到的一个网络问题,前天修改了虚拟机的主机名,重启虚拟机之后,使用新的主机名和IP都可以访问虚拟机,但昨天开启虚拟机之后,宿主机使用主机名和IP都不能访问虚拟机,于是,我通过ifconfi ...
- Unity3D RTS游戏中帧同步实现
帧同步技术是早期RTS游戏常用的一种同步技术,本篇文章要给大家介绍的是RTX游戏中帧同步实现,帧同步是一种前后端数据同步的方式,一般应用于对实时性要求很高的网络游戏,想要了解更多帧同步的知识,继续往下 ...
- 第八次作业(课堂实战)- 项目UML设计(团队)
1. 团队信息 队名:小白吃队 成员: 后敬甲 031602409 卢泽明 031602328 蔡文斌 031602301 葛亮 031602617 刘浩 031602423 黄泽 031602317 ...
- c++ 值转换
1.double,float 四舍五入,保留小数位数. void MainWindow::on_pushButton_clicked() { double number=3.141592; ); qD ...