博弈问题-取石子(D题小牛vs小客)附取石子游戏总结

题目:

链接:https://www.nowcoder.net/acm/contest/75/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

小牛和小客玩石子游戏,他们用n个石子围成一圈,小牛和小客分别从其中取石子, 谁先取完谁胜,每次可以从一圈中取一个或者相邻两个,每次都是小牛先取,请输出胜利者的名字(小牛获胜输出XiaoNiu,小客获胜输出XiaoKe)(1 2 3 4 取走 2 13 不算相邻)


输入描述:

输入包括多组测试数据
每组测试数据一个n(1≤n≤1e9)

输出描述:

每组用一行输出胜利者的名字(小牛获胜输出XiaoNiu,小客获胜输出XiaoKe)
代码:
package lanqiao;
/*
 链接:https://www.nowcoder.net/acm/contest/75/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述 
小牛和小客玩石子游戏,他们用n个石子围成一圈,小牛和小客分别从其中取石子,谁先取完谁胜,
每次可以从一圈中取一个或者相邻两个,
每次都是小牛先取,请输出胜利者的名字(小牛获胜输出XiaoNiu,小客获胜输出XiaoKe)
(1 2 3 4 取走 2 13 不算相邻)
输入描述:
输入包括多组测试数据
每组测试数据一个n(1≤n≤1e9)
输出描述:
每组用一行输出胜利者的名字(小牛获胜输出XiaoNiu,小客获胜输出XiaoKe)
示例1
输入

2
3
输出

XiaoNiu
XiaoKe
 */
import java.util.Scanner;
public class D_problem {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin=new Scanner(System.in);
		int n;
		while(cin.hasNext()) {//务必加上这个循环语句,否则无法完全通过。亲测。
		n=cin.nextInt();
		if(n>2) {
			System.out.println("XiaoKe");
		}
		else {
			System.out.println("XiaoNiu");
		}
		}
	}

}

附上一篇总结的比较好的取石子游戏的博客: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胜。

这里就是上面的D题解法。

取石子(四)

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

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

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

01. #include<stdio.h>
02. #include<math.h>
03. #include<iostream>
04. #include<algorithm>
05. using namespace std;
06. int main()
07. {
08. int a,b;
09. while(scanf("%d%d",&a,&b)!=EOF)
10. {
11. if(a<b)
12. swap(a,b);
13. if(floor((a-b)*((sqrt(5.0)+1.0)/2.0))==b)
14. printf("0\n");
15. else
16. printf("1\n");
17. }
18. }

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的表即可。

01. #include<stdio.h>
02. #include<math.h>
03. int a[100001][2];
04. int main()
05. {
06. int i;
07. for(i=1;i<=10000;i++)
08. a[i][0]=i*(sqrt(5.0)+1)/2,a[i][1]=a[i][0]+i;
09. int n;
10. while(scanf("%d",&n)!=EOF)
11. {
12. for(i=0;i<=n;i++)
13. printf("(%d,%d)",a[i][0],a[i][1]);
14. puts("");
15. }
16. }

取石子(八)

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

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

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

     核心代码:

     

01. for(i=1; i<=n; i++)
02. {
03. int c=i*(sqrt(5.0)+1.0)/2.0;
04. int d=c+i;
05. if(c>n) break;
06. if(c==m&&d<n)
07. printf("%d %d\n",m,d);
08. else if(d==m&&c<n)
09. printf("%d %d\n",c,m);
10. else if(d==n&&c<m)
11. printf("%d %d\n",c,n);
12. }

  取石子(六)

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

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

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

01. #include<stdio.h>
02. int main()
03. {
04. int N;
05. scanf("%d",&N);
06. while(N--)
07. {
08. int n,s=0,x;
09. scanf("%d",&n);
10. while(n--)
11. scanf("%d",&x),s^=x;
12. if(s)
13. printf("PIAOYI\n");
14. else
15. printf("HRDV\n");
16. }

 取石子(九)

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

   尼姆博弈的变种,统计一下所有数一下大于一的个数,并将所有数字异或一遍,若大于一的个数为0&&异或之后为0||大于一的个数大于0&&异或之后不为零,则A(Yougth)胜,否则B(Hrdv)胜,

   代码:

01. #include<stdio.h>
02. int main()
03. {
04. int nn;
05. scanf("%d",&nn);
06. while(nn--)
07. {
08. int n,x=0,s=0,z;
09. scanf("%d",&n);
10. while(n--)
11. {
12. scanf("%d",&z);
13. if(z>1)  s++;
14. x^=z;
15. }
16. if(x&&s||!x&&!s)
17. printf("Yougth\n");
18. else
19. printf("Hrdv\n");
20. }
21. }

取石子(二)

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

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

 

01. #include<stdio.h>
02. #include<string.h>
03. int main()
04. {
05. int nn;
06. scanf("%d",&nn);
07. while(nn--)
08. {
09. int n,a,b,c=0;
10. scanf("%d",&n);
11. while(n--)
12. {
13. scanf("%d%d",&a,&b);
14. a=a%(b+1);
15. c^=a;
16. }
17. if(c)
18. puts("Win");
19. else
20. puts("Lose");
21. }
22. }

取石子(五)

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

  具体过程:斐波那契博弈

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

代码:

01. #include<stdio.h>
02. long long a[110]={0,1};
03. int main()
04. {
05. long long i,n;
06. for(i=2;i<100;i++)
07. a[i]=a[i-1]+a[i-2];
08. while(scanf("%lld",&n)!=EOF)
09. {
10. int f=0;
11. for(i=1;i<100;i++)
12. if(a[i]==n)
13. {f=1;break;}
14. if(f)
15. printf("No\n");
16. else
17. printf("Yes\n");
18. }
19. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值