2.石头游戏(坑爹)
题目抽象:
一堆石子两个人轮流取,每次至少要取走一个。先取的人第一次可以取任意多个,但是不能全部取完。之后每个人取石子时,能取的数目最多不能超过对手刚才取的石子数的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.石头游戏(坑爹)相关推荐
- Nim 游戏 、⽯头游戏1、石头游戏2
Nim 游戏 .⽯头游戏1.石头游戏2 文章目录 Nim 游戏 .⽯头游戏1.石头游戏2 **一:Nim 游戏** **二:⽯头游戏** **三.石头游戏2** **方法一:DP 函数** **方法二 ...
- 算法作业2-轮流取石头游戏
两个足够聪明的人玩轮流取石头的游戏,谁取到最后一个石头谁就赢了,他们一次只能取1个.3个.7个或8个石头,写一程序判断n个石头时先取的人是输还是赢. 输入格式: 一个整数n,其值不超过10000000 ...
- acwing 206 石头游戏 矩阵快速幂
题目地址 构建1维数组f(num(i,j)) -> 表示第num(i,j) =((i-1)*m + j)位的石头有多少个.(i,j)表示一个位置 可以知道f的长度为n*m+1.令f[0] = 1 ...
- LeetCode:青蛙跳石头游戏
/* 有n块石头分别在x轴的0,1,...,n-1位置,一致青蛙在石头0,想跳到石头n-1,如果青蛙 在第i块石头上,它最多可以向右跳距离ai,问青蛙能否跳到石头n-1?示例1: Input:a=[2 ...
- 石头游戏[CH3401]
欢迎大家访问我的老师的OJ---caioj.cn 题面描述 传送门 思路 题目可以理解为是一个 n ∗ m n*m n∗m的矩阵,在里面进行一些玄学的操作. 不难发现,操作序列的长度不超过6,那么1~ ...
- 【HNOI2010】【BZOJ2000】stone 取石头游戏
BZOJ上的Source是骗子QAQ这题根本不是SG函数QAQ Description A 公司正在举办一个智力双人游戏比赛--取石子游戏,游戏的获胜者将会获得 A 公司提 供的丰厚奖金,因此吸引了来 ...
- 【bzoj2000】[Hnoi2010]stone 取石头游戏
Description A 公司正在举办一个智力双人游戏比赛--取石子游戏,游戏的获胜者将会获得 A 公司提 供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参加比赛. 与经典的取石子游戏相比 ...
- 取石头游戏 c语言,[HNOI2010]取石头游戏(博弈论+贪心)
题目描述: 有\\(n\\)堆石子,每堆石子的个数为\\(a_i\\),保证存在至少一堆石子个数为\\(0\\) 两个人,每个人每次可以取一堆石子,一堆石子可以被取当且仅当它相邻的石子有至少一堆为\\ ...
- 移动石头游戏中的博弈问题(洛谷P4136题题解,Java语言描述)
题目要求 P4136题目链接 分析 一道博弈论的题. 很显然,棋盘大小为 n×nn\times nn×n,左上角已有111枚棋子,那么剩下的可选格子有 n2−1n^2-1n2−1 个. 由题意得,如果 ...
最新文章
- 天津工业大学19年计算机考研大纲,2019年天津工业大学《计算机原理及接口技术》考研复试大纲...
- 吃饱了,就来写点东西吧。讲一个真实的故事给你长自信
- 第二节:简易安装 和 快速入门Vue.js
- 信息学奥数一本通(1004:字符三角形)
- poj 1502 单源最短路径
- Selenium下载页面上的图片
- 设置win7一直以管理员身份运行
- 又是一年毕业季,你拿什么打动面试官?
- redis manager desktop下载、安装、连接redis教程(官网)
- 微信小程序拼团功能之表结构
- mysql 重做日志 镜像_mysql重做日志 - osc_vr7hvjd2的个人空间 - OSCHINA - 中文开源技术交流社区...
- 图像特征之SURF特征匹配
- ubuntu 支持cuteFTP
- 再谈probit回归和logistic回归
- Yii2日志使用方法
- element-table 数据过多时浏览器卡死
- elementPlus 日期时间选择器设置24小时制失效
- 【MySQL】mysql | linux | 解决mysql cpu | cpu飙升 | cpu100% cpu占用过高
- 小米正式宣布:这种手机以后买不到了…
- JXL(JXLS)的使用:java中操作Excel的解决方案之一。
热门文章
- 最佳情侣身高差 Java版 PTA
- 华为2018实习面试+状态总结
- Ubuntu14.04解决关机不断电问题
- ping回显目标主机不可达destination host unreachable的含义及发生情况
- PageHelper这种情况下有坑!
- 《死亡搁浅》如何成了“薛定谔的猫”? 一个小岛秀夫式的乌托邦
- wp教程-wp详细教程-免费wordpress模板主题搭建教程
- java 调用 默认打印机 打印小票
- c语言学生成员管理代码报告怎么写,C语言学生通信录管理系统课程设计报告
- java记事本编译_Java记事本编译