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. 当一个 ...
随机推荐
- Spring MVC 注解相关
// required=false表示不传的话,会给参数赋值为null,required=true就是必须要有 @ResponseBody @RequestMapping("testRequ ...
- 【mmall】url-pattern配置为"/"和"/*"的区别
我的代码 <!-- springmvc --> <servlet> <servlet-name>springmvc</servlet-name> < ...
- view类初探(一)
/*************************************************************************************************** ...
- 【Convex Optimization (by Boyd) 学习笔记】Chapter 2 - Convex sets(1) 仿射集&凸集
I. 仿射凸集(Affine and convex sets) 1. 线与线段 假设\(R^n\)空间内两点\(x_1,x_2\, (x_1≠x_2)\),那么\(y=\theta x_1+(1-\t ...
- C# 事务 四种事务隔离级别
http://www.zsythink.net/archives/1233 不同隔离级别的问题 脏读(Dirty Read) 一个事务处理过程里读取了另一个未提交的事务中的数据 例子: 当一个事务 ...
- HSV color space
计算机图形学原理的课给我们指定了课题然后自己去研究并且做ppt(顺便吐槽一下晚课下课布置作业第二天早课就要交的辣鸡时间安排) 肝了一个晚上 大概知道了一点 先写下来 HSV其实是hue saturat ...
- nginx 配置域名转发
自己测试环境,配置下载目录和一个jenkins的地址: 域名跳转,反向代理 # cat ../nginx.conf user www www; worker_processes ; error_log ...
- 卷积神经网络(matlab实现)
卷积神经网络是看matlab 的一个toolbox入的门: https://github.com/rasmusbergpalm/DeepLearnToolbox 还有一篇原理推导文献,全是公式: ht ...
- Git学习笔记01-安装Git
学习的资料来自廖雪峰官方网站的Git教程,菜鸟教程的Git教程 Git是一个分布式版本控制工具,在windows上使用Git可以直接从官网下载,然后默认选项安装即可. 安装完成后,在开始菜单中找到找到 ...
- ansible笔记(5):常用模块之文件操作(二)
ansible笔记():常用模块之文件操作(二) 文件操作类模块 find模块 find模块可以帮助我们在远程主机中查找符合条件的文件,就像find命令一样. 此处我们介绍一些find模块的常用参数, ...