转载自:http://blog.csdn.net/acmlzq/article/details/51212297

nyoj的取石子有好多道,除了两道难度为6的,剩下的在这儿简单总结一下结论。

取石子(一)

有一堆石子共有n个,A和B轮流取,A先,每次最少取1个,最多取m个,先取完者胜,A,B足够聪明,问谁先胜?

比较简单的巴什博弈,若n%(m+1)!=0,A胜,否则B胜。

取石子(七)

n个石子摆成一圈,A和B轮流取,每次可以从中取一个或相邻两个,先取完者胜,A先取,问谁胜?

若n==1||n==2 则A胜,否则B胜。

取石子(四)

两堆石子分别n,m(n>=m)个,A和B轮流取,有两种取法,一是在任意的一堆中取走任意多的石子,最少为一;二是在两堆中同时取走相同数量的石子。A先取,先取完者胜,问A是否胜?(胜输出1,负为0)

著名的威佐夫博奕,题解链接:威佐夫博弈,

结论:若(n-m)*(sqrt(5.0)+1.0)/2.0!=m  ,则A胜,否则负。

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=161

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
double solve(int n)
{double m=(double)n;return (sqrt(5)+1)/2*m;
}
int main()
{int a,b;while(~scanf("%d%d",&a,&b)){if(a>b)swap(a,b);if((int)solve(b-a)==a){printf("0\n");}else{printf("1\n");}}return 0;
}

Wyothoff Game

题意同上取石子(四),不过现在要求前n(n<=10W)个必败态,比如A面对(0,0)必败,面对(1,2)(3,5)(4,7)也必败,现在给一个n,求前n个必败态。

由上面取石子(四)的题解链接可知其第n项为(n*(sqrt(5.0)+1.0)/2,n*(sqrt(5.0)+1.0)/2+n),由此打一个10W的表即可。

http://acm.nyist.net/JudgeOnline/problem.php?pid=837

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int  maxn =100000+100;
double solve(int n)
{double m=(double)n;return (sqrt(5)+1)/2*m;
}
int a[maxn][2];int main()
{for(int i=0;i<maxn;i++){a[i][0]=(int)solve(i);a[i][1]=a[i][0]+i;}int n;while(~scanf("%d",&n)){for(int i=0;i<n;i++){printf("(%d,%d)",a[i][0],a[i][1]);}printf("(%d,%d)\n",a[n][0],a[n][1]);}return 0;
}

取石子(八)

题意同上上取石子(四),依然为威佐夫博弈,但是如果A胜,要你输出你第一次怎么取子,(如果在任意的一堆中取走石子能胜同时在两堆中同时取走相同数量的石子也能胜,先输出取走相同数量的石子的情况,假如取一堆的有多种情况,先输出从石子多的一堆中取的情况,且要求输出结果保证第二个值不小于第一个值。)

首先判断若n==0,则直接输出(0,0);

else   for循环从头到尾把上面Wyothoff Game的第n项公式循环一遍,并分别与n,m比较。

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=886

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
int main()
{int a,b,t;double p=(1.0+(sqrt(5.0)))/2;//威佐夫博奕公式while(scanf("%d%d",&a,&b)&&a!=0||b!=0){if(a>b)swap(a,b);int s=b-a;int k=floor(s*p);if(k==a)//判断是否是必胜局面printf("0\n");else{printf("1\n");if(a-k==b-(k+s)&&a>=k)//拿走相同数量的石子  注意两个条件都要写,不然WAprintf("%d %d\n",k,k+s);for(int i=0; ;i++){int temp=i*p;if(temp>=b)break;if(b>temp+i&&a==temp)//从b中拿石子,且拿完b比a大printf("%d %d\n",temp,temp+i);else if(a==temp+i)//从b中拿石子,但拿完b比a小printf("%d %d\n",temp,temp+i);else if(b==temp+i&&a>temp)//从a中拿,拿完肯定a还是小于bprintf("%d %d\n",temp,temp+i);}}}return 0;
}

取石子(六)

有n堆石子,每堆石子都有任意个,A和B轮流从取任意堆里取一定的石子,每次只能从一堆里至少取一个,A先取,先取完者胜,问谁胜?

此题为尼姆博弈,题解链接:尼姆博弈;

结论:将n个数异或一遍,若不为0,则A胜,否则B胜。

#include<stdio.h>
int main()
{int s,n;scanf("%d",&s);while(s--){scanf("%d",&n);int sum=0;int x;for(int i=0;i<n;i++){scanf("%d",&x);sum^=x;}if(sum!=0)printf("PIAOYI\n");elseprintf("HRDV\n");}return 0;
}

取石子(九)

题意同取石子(六),不过先取完者败,问谁胜?

在尼姆博奕中取完最后一颗石子的人为赢家,而取到最后一颗石子为输家的就是反尼姆博奕。这道题就反尼姆

博奕的模型。在尼姆博奕中判断必胜局面的条件是所有堆石子数目相异或不等于0 。  而在反尼姆博奕中判断必胜局

面的条件有两点,满足任意一点先手都能取胜,即必胜局面。

1:各堆石子数目异或结果不等于0,且存在有石子数目大于1的石子堆。

2:各堆石子数目异或结果等于0,且所有石子堆数目全部为1。

代码:

#include<cstdio>
int main()
{int ans,n,m,cnt,num;scanf("%d",&n);while(n--){scanf("%d",&m);ans=0;num=0;while(m--){scanf("%d",&cnt);ans^=cnt;if(cnt>1)num++;}if((ans&&num)||(!ans&&!num))printf("Yougth\n");elseprintf("Hrdv\n");} return 0;
} 

取石子(二)

题意同上上取石子(六),不过限定了每堆石子最多可以取的石子数(最少为一),问A是胜还是败?(第一行是一个整数T表示测试数据的组数(T<100)每组测试数据的第一行是一个整数N(1<N<100),表示共有N堆石子,随后的N行每行表示一堆石子,这N行中每行有两个数整数m,n表示该堆石子共有m个石子,该堆石子每次最多取n个。

(0<=m,n<=2^31))

尼姆博弈和巴什博奕的结合

题目思路:每一堆的必胜状态是 m%(n+1) 然后对每一堆的最优解进行异或,如果是非平衡状态则先手必胜,否则先手必败。

http://acm.nyist.net/JudgeOnline/problem.php?pid=135

#include<stdio.h>
int main(){  int t;  scanf("%d",&t);  while(t--){  int N;  int sum=0;  scanf("%d",&N);  for(int i=1;i<=N;i++){  int n,m;  scanf("%d%d",&n,&m);  sum^=n%(m+1);  }   if(sum) puts("Win");  else puts("Lose");  }  return 0;
}   

取石子(五)

有一堆石子,A和B轮流从中取一定的石子,但规定:第一次不能取完,至少一个;从第二次开始,每个人取的石子数至少为1,至多为对手刚取的石子数的两倍。A先取,问A是否会胜?

具体过程:斐波那契博弈

结论:若其对应的石子数目刚好是斐波那契数,则A必败,否则A必胜。

详细解释:

结论:当n为fibonacci数时,先手必败(n >= 2);

证明:

参考资料:http://blog.csdn.net/dgq8211/article/details/7602807

以下为个人思路:

根据“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和(优先选取最大的)。

比如 n = 14 时, n = 8 + 5 + 1;而先手要赢的条件是,先手必须要先取完最小的一堆,再取完次小的一堆,以此类推,并保证每堆的最后一个是自己取到的而且不能取超!听起来有点绕,举个例子:

1、先看必胜态,n不是fibonacci数的时候,令n = 9 =5 + 3 + 1:

a、先手先取最小的一堆,1个,保证了最后一个是自己取得;

b、此时后手开始取次小的一堆(3个石子),上面说过,要想赢的话,要保证这一堆的第3个必须是自己取得;此时后手有 1个、2个两种取法,但此处无论后手怎么取,都能保证这一堆的最后一个(第3个)是自己取得;

c、此时后手开始取最后一堆(5个石子),b步先手可能取得是1或2,因此此步后手可能有1、2、3、4四种取法,易知后手取3或4的话,自己立马就能取到最后一个,就赢了,而取1或2时,同上(读者自己来),仍能保证取到最后一个(此堆第5个,全局最后一个),必赢!

2、再说必败态,若n本身是fibonacci数时,已经不需要分解了,为方便观察,令n=5:

实际上与上面相同,每一堆(有fib个石子)在自己先手的情况下,无论怎么取,后手都能保证自己取到这一堆的最后一个,因此后手必胜!

  PS:所以上面说总石子数为非fibonacci数时先手必胜的原因在于,总数目分解为若干fib数时,先手先全部取走最小的一堆1个(也是取到了这一堆的最后一个),以后每堆(有fib[i]个石子)都是后手先取,先手便有把握取到这一堆的最后一个了!

#include <stdio.h>
#define N 100long long fib[N];void Fib()
{fib[0] = 0;fib[1] = 1;for(int i = 2; i < N; i ++){fib[i] = fib[i - 1] + fib[i - 2];}
}int main()
{Fib();long long n;while(scanf("%lld", &n) != EOF){bool is_fib = 0;for(int i = 2; i < 100; i ++){if(fib[i] == n){is_fib = 1;break;}}if(is_fib)printf("No\n");elseprintf("Yes\n");}return 0;
}

NYOJ 取石子总结相关推荐

  1. NYOJ 23 取石子

    取石子(一) 时间限制:3000 ms  | 内存限制:65535 KB 难度:2 描述 一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子.游戏的规 ...

  2. NYOJ 888 取石子(九)

    取石子(九) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 最近TopCoder的Yougth和Hrdv在玩一个游戏,游戏是这样的. 有n堆石子,两个人轮流从其中某一堆 ...

  3. NYOJ 833 取石子(七)

    取石子(七) 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 Yougth和Hrdv玩一个游戏,拿出n个石子摆成一圈,Yougth和Hrdv分别从其中取石子,谁先取完者胜 ...

  4. NYOJ 585 取石子(六)

    取石子(六) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 最近TopCoder的PIAOYI和HRDV很无聊,于是就想了一个游戏,游戏是这样的:有n堆石子,两个人轮流 ...

  5. NYOJ 358 取石子(五)

    取石子(五) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 himdd最近很想玩游戏,于是他找到acmj和他一起玩,游戏是这样的:有一堆石子,两个人轮流从其中取走一定的 ...

  6. NYOJ 161 取石子(四)

    取石子 (四) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意 ...

  7. NYOJ 137 取石子(三)

    取石子(三) 时间限制:1000 ms  |  内存限制:1000 KB 难度:6 描述 小王喜欢与同事玩一些小游戏,今天他们选择了玩取石子. 游戏规则如下:共有N堆石子,已知每堆中石子的数量,两个人 ...

  8. NYOJ 135 取石子(二)

    取石子(二) 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 小王喜欢与同事玩一些小游戏,今天他们选择了玩取石子. 游戏规则如下:共有N堆石子,已知每堆中石子的数量,并且 ...

  9. NYOJ 23 取石子(一)

    取石子(一) 时间限制:3000 ms  |  内存限制:65535 KB 难度:2 描述 一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子.游戏的 ...

  10. 【NYOJ】取石子系列总结(十一题全)

    取石子(一) 基础的巴什博奕 巴什博奕的重点是只有一堆, 如果n % (m + 1) != 0 则先手赢,如果用普通的数组会TLE. 证明:如果n = m + 1,先手最多拿m个,肯定有剩下的,所以先 ...

最新文章

  1. 小型化RDA5807调频收音模块实验板
  2. Coding之路——重新学习C++(2):static的详细理解
  3. String、StringBuffer、StringBuilder介绍
  4. 最好用的markdown编辑器推荐typora
  5. matlab常用函数——软件常用函数
  6. 体验AJAX Toolkit新控件:AutoCompleteExtender
  7. matlab randi 函数,MATLAB中的randi函数
  8. 滴滴披露女司机数据:80后女性过半 24%全年零违章
  9. linux设置不同地址,ubuntu20.04设置静态ip地址(包括不同版本)
  10. 新生儿操作系统操作手册
  11. 无法识别依赖属性_设计模式起步-UML学习 - 认识UML类图(依赖)
  12. AndroidStudio打开的Gradle项目不识别成相应文件,gradle无响应
  13. L3-015 球队“食物链” (30 分)
  14. 值得收藏!中国金融体系主要指标大全
  15. 智慧城市数字孪生技术方案,建设可视化系统
  16. MATLAB GUI中的handles
  17. 使用python获取win10锁屏照片
  18. mysql 查找差值最小_mysql获取两个表中日期字段的最小差值
  19. 办公室装修的五要四不要
  20. 游戏编程模式之组件模式

热门文章

  1. UnityWebPlayer缓存清理工具
  2. Dev C++使用教程(使用Dev C++编写C语言程序)
  3. kali linux下sqlmap使用教程
  4. ODBC数据源的作用及配置
  5. FPS游戏-罗技鼠标-通用的压枪宏
  6. matlab软件安装码,Matlab2017a软件安装包以及安装教程
  7. 小米蓝牙音响驱动_广场舞阿姨的最爱,户外野营者的必备,小米华为都甘拜下风的便携音箱...
  8. Twitter被封怎么办?
  9. vim编辑器常用命令整理
  10. Java语言程序设计(第3版)沈泽刚主编第6,7,8章课后习题答案