题目大意:

有K堆石子,每堆有Ki个。两人的操作能够是:

            1 从某一堆拿走一个 假设该堆在此之后没有石子了。就消失

            2 合并两个堆

       求是否先手必胜,先手胜输出Alice。否则输出Bob

思路:

这道题读完后毫无头绪。推了半天也推不个所以然来,參看大神代码后,感觉就是一个记忆化搜索啊,唉,知识学多了不会用还是白搭。还得多做题啊!

这里我们把数字分成 1,2,大于等于3的奇数,大于等于4的偶数四类。

       这样分的原因在于。一个大于3的奇数是实际上等价于3的;由于每当对手减一个。自己也减一个。就又变回了一个大于3的奇数。终于变成3。

同理。全部大于2的偶数等价于4。

       所以我们用dp[a][b][c][d]表示有a个1,b个2,c个3,d个4是不是一个必胜态,然后动规求解就好了。

代码:

#include <stdio.h>
#define N 51 bool dp[N][N][N][N] = {0};
bool vis[N][N][N][N] = {0}; int F(int a, int b, int c, int d) // 一个相似记忆化搜索的过程
{
if(!vis[a][b][c][d]){ // 假设后继状态为P状态,则此状态为N状态
if(a >= 1 && !F(a - 1, b, c, d)) dp[a][b][c][d] = 1; // 从 a 中某堆拿走一个。消失
if(b >= 1 && !F(a + 1, b - 1, c, d)) dp[a][b][c][d] = 1; // 从 b 中某堆拿走一个。变成 a
if(c >= 1 && !F(a, b + 1, c - 1, d)) dp[a][b][c][d] = 1; // 从 c 中某堆拿走一个。变成 b
if(d >= 1 && !F(a, b, c + 1, d - 1)) dp[a][b][c][d] = 1; // 从 d 中某堆拿走一个,变成 c if(a >= 2 && !F(a - 2, b + 1, c, d)) dp[a][b][c][d] = 1; // 合并 a 中的两堆,变成 b 类的一堆
if(b >= 2 && !F(a, b - 2, c, d + 1)) dp[a][b][c][d] = 1; // 合并 b 中的两堆,变成 d 类的一堆
if(c >= 2 && !F(a, b, c - 2, d + 1)) dp[a][b][c][d] = 1; // 合并 c 中的两堆,变成 d 类的一堆
if(d >= 2 && !F(a, b, c, d - 2 + 1)) dp[a][b][c][d] = 1; // 合并 d 中的两堆,变成 d 类的一堆 if(a >= 1 && b >= 1 && !F(a - 1, b - 1, c + 1, d)) dp[a][b][c][d] = 1; // 合并 a、b 中的一堆,变成 c 类的一堆
if(a >= 1 && c >= 1 && !F(a - 1, b, c - 1, d + 1)) dp[a][b][c][d] = 1; // 合并 a、c 中的一堆。变成 d 类的一堆
if(a >= 1 && d >= 1 && !F(a - 1, b, c + 1, d - 1)) dp[a][b][c][d] = 1; // 合并 a、d 中的一堆,变成 c 类的一堆
if(b >= 1 && c >= 1 && !F(a, b - 1, c - 1 + 1, d)) dp[a][b][c][d] = 1; // 合并 b、c 中的一堆,变成 c 类的一堆
if(b >= 1 && d >= 1 && !F(a, b - 2, c, d - 1 + 1)) dp[a][b][c][d] = 1; // 合并 b、d 中的一堆。变成 d 类的一堆
if(c >= 1 && d >= 1 && !F(a, b, c - 1 + 1, d - 1)) dp[a][b][c][d] = 1; // 合并 c、d 中的一堆,变成 c 类的一堆 vis[a][b][c][d] = 1;
} return dp[a][b][c][d];
} int main()
{
int loop, n, t, ct = 1;
int a, b, c, d, ans; // a 表示仅仅有一个石子的堆数,b 表示有仅仅有两个石子的堆数。c 表示有奇数个石子的堆数, d 表示有偶数个石子的堆数
scanf("%d", &loop);
while(ct <= loop){
scanf("%d", &n);
a = b = c = d = 0;
for(int i = 0; i < n; i ++){
scanf("%d", &t);
if(t == 1) a ++;
else if(t == 2) b ++;
else if(t % 2 == 1) c ++;
else d ++;
} ans = F(a, b, c, d);
printf("Case #%d: ", ct ++);
if(ans)
printf("Alice\n");
else
printf("Bob\n");
} return 0;
}

2011 ACM-ICPC 成都赛区A题 Alice and Bob (博弈动规)的更多相关文章

  1. 2011 ACM/ICPC 成都赛区(为2013/10/20成都现场赛Fighting)

    hdu 4111  Alice and Bob 博弈:http://www.cnblogs.com/XDJjy/p/3350014.html hdu 4112 Break the Chocolate ...

  2. 2013年山东省第四届ACM大学生程序设计竞赛E题:Alice and Bob

    题目描述 Alice and Bob like playing games very much.Today, they introduce a new game. There is a polynom ...

  3. hdu 4461 第37届ACM/ICPC杭州赛区I题

    题意:给两个人一些棋子,每个棋子有其对应的power,若b没有或者c没有,或者二者都没有,那么他的total power就会减1,total power最少是1,求最后谁能赢 如果b或c出现的话,fl ...

  4. hdu 4460 第37届ACM/ICPC杭州赛区H题 STL+bfs

    题意:一些小伙伴之间有朋友关系,比如a和b是朋友,b和c是朋友,a和c不是朋友,则a和c之间存在朋友链,且大小为2,给出一些关系,求出这些关系中最大的链是多少? 求最短路的最大距离 #include& ...

  5. zoj 3662 第37届ACM/ICPC长春赛区H题(DP)

    题目:给出K个数,使得这K个数的和为N,LCM为M,问有多少种 f[i][j][k]表示选i个数,总和为j,最小公倍数为k memery卡的比较紧,注意不要开太大,按照题目数据开 这种类型的dp也是第 ...

  6. 2017 ACM/ICPC 新疆赛区 I 题 A Possible Tree 带权并查集

    传送门 题意:给定一棵带权树的形态, 但是并不知道每天条边的具体权重. 然后给m个信息, 信息格式为u v val, 表示在树上u 到 v 的路径上经过的边的权重的异或和为val, 问前面最多有多少个 ...

  7. hdu 4462 第37届ACM/ICPC 杭州赛区 J题

    题意:有一块n*n的田,田上有一些点可以放置稻草人,再给出一些稻草人,每个稻草人有其覆盖的距离ri,距离为曼哈顿距离,求要覆盖到所有的格子最少需要放置几个稻草人 由于稻草人数量很少,所以状态压缩枚举, ...

  8. hdu 4463 第37届ACM/ICPC杭州赛区K题 最小生成树

    题意:给坐标系上的一些点,其中有两个点已经连了一条边,求最小生成树的值 将已连接的两点权值置为0,这样一定能加入最小生成树里 最后的结果加上这两点的距离即为所求 #include<cstdio& ...

  9. hdu 4438 第37届ACM/ICPC 天津赛区现场赛H题

    题意:Alice和Bob两个人去打猎,有两种(只)猎物老虎和狼: 杀死老虎得分x,狼得分y: 如果两个人都选择同样的猎物,则Alice得分的概率是p,则Bob得分的概率是(1-p): 但是Alice事 ...

随机推荐

  1. Android 关于文件及文件夹的创建 、删除、重命名、复制拷贝

    package com.example.administrator.myapplication.util; import java.io.BufferedReader;import java.io.B ...

  2. QList模板类常用接口函数

    插入操作:insert()函数原型:void QList::insert(int i, const T &value) 在索引后插入值 i:索引 value:插入值 Example: QLis ...

  3. CREATE TRIGGER - 定义一个新的触发器

    SYNOPSIS CREATE TRIGGER name { BEFORE | AFTER } { event [ OR ... ] } ON table [ FOR [ EACH ] { ROW | ...

  4. Ubuntu-11.10中 vim和Gedit打开html文件中文乱码问题

    解决vim中文乱码方法:     打开/etc/vim/vimrc     添加代码:     set fileencodings=utf-8,gb2312,gbk,gb18030     set t ...

  5. JavaSE-13 内部类

    学习要点 内部类的定义 内部类的应用 内部类 定义 Java的一个类中包含着另一类. A类和B类是C类的外部类.B类是C类的外部类.A类也称为顶层类. 如何使用内部类 public class MyF ...

  6. 第3节 mapreduce高级:7、自定义outputformat实现输出到不同的文件夹下面

    2.1 需求 现在有一些订单的评论数据,需求,将订单的好评与差评进行区分开来,将最终的数据分开到不同的文件夹下面去,数据内容参见资料文件夹,其中数据第九个字段表示好评,中评,差评.0:好评,1:中评, ...

  7. div 可视化区域弹窗居中

    效果: css: .div_alt { position: fixed; border-radius: 5px; top: 50%; left: 50%; width: auto; min-width ...

  8. SpringBoot 全局处理以及注入请求参数

    后端接口,经常会用token获取对应的账号信息.于是考虑将这个步骤封装起来. 之前项目使用ThreadLocal去做这样的事情,但昨天看SpringBoot的官方文档,发现借助框架的功能也可以做这样的 ...

  9. JavaScript中数据类型的转换规则

    JavaScript中数据类型的转换规则 制作人:全心全意 JavaScript是一种无类型语言,也就是说,在声明变量时无须指定数据类型,这使得JavaScript更具有灵活性和简单性. 在代码执行过 ...

  10. 数组排序函数-php数组函数(一)

    数组排序,共13个 函数中有u的,能自定义比较函数:有k的,按照键来排序:有r(reverse)的,倒序:有a(association)的,一定是键值关联,除了rsort() usort() sort ...