题目抽象:

一堆石子两个人轮流取,每次至少要取走一个。先取的人第一次可以取任意多个,但是不能全部取完。之后每个人取石子时,能取的数目最多不能超过对手刚才取的石子数的k倍(k为给定常量)。取走最后一个石子的人算赢。

在两个人都以最优策略进行游戏时,先手要么必胜要么必负,必胜还是必负取决于一开始有多少个石子,本题就是告诉你开始的石子数目,你需要判断先手必胜还是先手必负,然后对先手必胜的情况,要算出先手一方第一次至少需要取多少颗石子。

解题思路:

首先根据提示我们可以知道先手负的局面都是一些特殊局面,并且数量远少于先手胜的局面,因此分析主要针对先手负的局面进行,提示中的信息给了一个很好的入手点,我们先对k=1时的性质进行分析:

先手负的初始石子数序列为{1,2,4,8,...},通过观察规模比较小的数据不难发现,若初始石子数n不是2的幂,则取石子数最少的必胜走法恰是n用二进制表示时最后一个1所代表的数值,比如n用二进制数表示是11011010时,必胜取法为2(10)。先手取走这“最后一个1”之后,由于k=1,后手取的石子数至多和先手一样多,所以后手无法取走剩下的石子中的“最后一个1”,假如我们能证明后手取完之后先手仍然能取走剩下石子中的“最后一个1”,那么我们就证明了只要一直取走“最后一个1”,先手就能够保证取胜。事实上对于2^p以及任意一个满足x<2^p的正整数x,2^p-x用二进制表示时的“最后一个1”代表的数值必然不大于x,于是,只要有一方无法取完当前石子数的“最后一个1”,另一方就一定可以取走剩下石子数的“最后一个1”,因此,在初始石子为2的幂时,先手无法取走“最后一个1”(第一次无法取走全部石子),胜利就属于对方啦,而只要初始石子数不是2的幂,先手就能保证胜利。

然后分析k=2时的情形:

先手负的初始石子数序列为{1,2,3,5,8,13,21,...},正好是Fibonacci数列,而观察小规模数据可以发现,先手取胜时取走的最少石子数也是Fibonacci数列中的数。对于Fibonacci数列,有以下性质:

性质1:任何一个正整数都可以分解为Fibonacci数列中一些不相邻的数的和,且分解方法唯一。且这些数{fk1,fk2,...fkt}满足2fk1<fk2,2fk2<fk3,...2fk(t-1)<fkt。

例如:前1个数有1种取法,即:{1}

前2个数有2种取法,即:{1},{2}

前3个数有4种取法,即:{1},{2},{3},{1,3}

前4个数有7种取法,即:{1},{2},{3},{1,3},{5},{5,1},{5,2}

前n个数的取法为:<前n-1个数的所有取法>,{fn},{fn+<前n-2个数的所有取法>}

性质2:k=2时,如果初始石子数n不是Fibonacci数,则可以把n分解为一些不相邻的Fibonacci数的和,在该分解方案里的最小的数,即是取石子数最少的获胜方法。

#include<stdio.h>

#define MAXM 1000000

int n,k;

int a[MAXM+1];//记录Fibonacci数列的前几个数

int r[MAXM+1];//记录上述前几个数的至多取法

void Solve()//优秀的男人总是坚持到了最关键的一个函数

{

int i,j;

a[0]=0;

r[0]=0;

for(i=1,j=0;i<MAXM;i++)//首先由于a数组记录的是Fibonacci数列中的数值,所以初始下标应该为1,而这里j为0的原因一是由于后期有循环函数可以使得其变为i-2的情况,因为我们发现r(n)=r(n-1)+1+r(n-2),所以这里的j应该满足i-2,但是一开始在i=1,2时j不存在,所以一开始设置为0,不影响i=1,2这两种情况

{

a[i]=r[i-1]+1;//这里也是直接观察前面的性质1得到的

while(j+1<i&&a[j+1]*k<a[i])//这里是一个很厉害的设计,如果只满足j+1<i的话,那么在a[2]时,j就会变为1,后面进行r[i]=a[i]+r[j]就会出错,所以这里又要求a[j+1]*k<a[i],这样就能避免i=1,2时j已经发生改变。其实也不用那么麻烦要限制两个条件,直接用a[j+1]*k<a[i]就可以了

{

j++;//使j变为i-2

}

r[i]=a[i]+r[j];//这里也是由性质一的来推导出来,其实就是r(n)=r(n-1)+1+r(n-2)

if(a[i]>=n)  break;//对a数组的要求只要达到Fibonacci数列中的某一个数就行,这个数必须大于或者等于此时石子数

}

if(i>MAXM)//避免石子数太多,这样就不好玩了

{

printf("un solvable\n");//就是吊,老子不玩了

return;

}

if (a[i]=n)//如果石子数刚好满足Fibonacci数列中的数的话,那没办法了,先手必输

{

printf("lose\n");

return;

}

for(;i>=1;i--)//进行到这一步时就说明此时的a[i]>n的,也就是先手必胜,所以按从大到小的顺序从n中减去Fibonacci数列中<n的数直到出现结果与Fibonacci数列中的数相等,就输出此时的n值,也就是先手胜时第一手应该取出多少石子

{

if(n==a[i])//这就是最后一步,通过下面的相减,得到结果与Fibonacci数列中的数相等,也就是先手胜时第一手应该取出多少石子

{

printf("%d\n",n);

return;

}

else if (n>a[i])//这里分别减去Fibonacci数列中小于n的值,直到后期满足n==a[i]

{

n-=a[i];

}

}

printf("logic error\n");//来自一种神秘的意外,莫名其妙的错误,编译器的错

}

int main()

{

int ca,cc=0;

scanf("%d",&ca);//总共进行多少次实验

while(ca-->0)

{

scanf("%d %d",&n,&k);//其中n表示石子数,k表示题目中给定常量

printf("Case %d:",++cc);

Solve();//这里进行先手必胜或者必负的判断,首先判断n是否在Fibonacci数列中,在的话,就先手必负,输出lose,否则,按从大到小的顺序从n中减去Fibonacci数列中<n的数直到出现结果与Fibonacci数列中的数相等,就输出此时的n值,也就是先手胜时第一手应该取出多少石子

}

return 0;

}

2.石头游戏(坑爹)相关推荐

  1. Nim 游戏 、⽯头游戏1、石头游戏2

    Nim 游戏 .⽯头游戏1.石头游戏2 文章目录 Nim 游戏 .⽯头游戏1.石头游戏2 **一:Nim 游戏** **二:⽯头游戏** **三.石头游戏2** **方法一:DP 函数** **方法二 ...

  2. 算法作业2-轮流取石头游戏

    两个足够聪明的人玩轮流取石头的游戏,谁取到最后一个石头谁就赢了,他们一次只能取1个.3个.7个或8个石头,写一程序判断n个石头时先取的人是输还是赢. 输入格式: 一个整数n,其值不超过10000000 ...

  3. acwing 206 石头游戏 矩阵快速幂

    题目地址 构建1维数组f(num(i,j)) -> 表示第num(i,j) =((i-1)*m + j)位的石头有多少个.(i,j)表示一个位置 可以知道f的长度为n*m+1.令f[0] = 1 ...

  4. LeetCode:青蛙跳石头游戏

    /* 有n块石头分别在x轴的0,1,...,n-1位置,一致青蛙在石头0,想跳到石头n-1,如果青蛙 在第i块石头上,它最多可以向右跳距离ai,问青蛙能否跳到石头n-1?示例1: Input:a=[2 ...

  5. 石头游戏[CH3401]

    欢迎大家访问我的老师的OJ---caioj.cn 题面描述 传送门 思路 题目可以理解为是一个 n ∗ m n*m n∗m的矩阵,在里面进行一些玄学的操作. 不难发现,操作序列的长度不超过6,那么1~ ...

  6. 【HNOI2010】【BZOJ2000】stone 取石头游戏

    BZOJ上的Source是骗子QAQ这题根本不是SG函数QAQ Description A 公司正在举办一个智力双人游戏比赛--取石子游戏,游戏的获胜者将会获得 A 公司提 供的丰厚奖金,因此吸引了来 ...

  7. 【bzoj2000】[Hnoi2010]stone 取石头游戏

    Description A 公司正在举办一个智力双人游戏比赛--取石子游戏,游戏的获胜者将会获得 A 公司提 供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参加比赛. 与经典的取石子游戏相比 ...

  8. 取石头游戏 c语言,[HNOI2010]取石头游戏(博弈论+贪心)

    题目描述: 有\\(n\\)堆石子,每堆石子的个数为\\(a_i\\),保证存在至少一堆石子个数为\\(0\\) 两个人,每个人每次可以取一堆石子,一堆石子可以被取当且仅当它相邻的石子有至少一堆为\\ ...

  9. 移动石头游戏中的博弈问题(洛谷P4136题题解,Java语言描述)

    题目要求 P4136题目链接 分析 一道博弈论的题. 很显然,棋盘大小为 n×nn\times nn×n,左上角已有111枚棋子,那么剩下的可选格子有 n2−1n^2-1n2−1 个. 由题意得,如果 ...

最新文章

  1. 天津工业大学19年计算机考研大纲,2019年天津工业大学《计算机原理及接口技术》考研复试大纲...
  2. 吃饱了,就来写点东西吧。讲一个真实的故事给你长自信
  3. 第二节:简易安装 和 快速入门Vue.js
  4. 信息学奥数一本通(1004:字符三角形)
  5. poj 1502 单源最短路径
  6. Selenium下载页面上的图片
  7. 设置win7一直以管理员身份运行
  8. 又是一年毕业季,你拿什么打动面试官?
  9. redis manager desktop下载、安装、连接redis教程(官网)
  10. 微信小程序拼团功能之表结构
  11. mysql 重做日志 镜像_mysql重做日志 - osc_vr7hvjd2的个人空间 - OSCHINA - 中文开源技术交流社区...
  12. 图像特征之SURF特征匹配
  13. ubuntu 支持cuteFTP
  14. 再谈probit回归和logistic回归
  15. Yii2日志使用方法
  16. element-table 数据过多时浏览器卡死
  17. elementPlus 日期时间选择器设置24小时制失效
  18. 【MySQL】mysql | linux | 解决mysql cpu | cpu飙升 | cpu100% cpu占用过高
  19. 小米正式宣布:这种手机以后买不到了…
  20. JXL(JXLS)的使用:java中操作Excel的解决方案之一。

热门文章

  1. 最佳情侣身高差 Java版 PTA
  2. 华为2018实习面试+状态总结
  3. Ubuntu14.04解决关机不断电问题
  4. ping回显目标主机不可达destination host unreachable的含义及发生情况
  5. PageHelper这种情况下有坑!
  6. 《死亡搁浅》如何成了“薛定谔的猫”? 一个小岛秀夫式的乌托邦
  7. wp教程-wp详细教程-免费wordpress模板主题搭建教程
  8. java 调用 默认打印机 打印小票
  9. c语言学生成员管理代码报告怎么写,C语言学生通信录管理系统课程设计报告
  10. java记事本编译_Java记事本编译