博弈论专题

1.巴什博奕(Bash Game)

取石子(一)

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 2
描述
一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子。游戏的规则是这样的。设有一堆石子,数量为N(1<=N<=1000000),两个人轮番取出其中的若干个,每次最多取M个(1<=M<=1000000),最先把石子取完者胜利。我们知道,TT和他/她的室友都十分的聪明,那么如果是TT先取,他/她会取得游戏的胜利么?
输入
第一行是一个正整数n表示有n组测试数据
输入有不到1000组数据,每组数据一行,有两个数N和M,之间用空格分隔。
输出
对于每组数据,输出一行。如果先取的TT可以赢得游戏,则输出“Win”,否则输出“Lose”(引号不用输出)
样例输入
2
1000 1
1 100
样例输出
Lose
Win

#include <stdio.h>

int main(){
	int t, n, m;
	scanf("%d", &t);
	while(t--){
		scanf("%d%d", &n, &m);
		printf(n % (m+1) ? "Win\n" : "Lose\n");
	}
	return 0;
}

2.尼姆博弈(Nimm Game)

取石子(二)

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 5
描述

小王喜欢与同事玩一些小游戏,今天他们选择了玩取石子。

游戏规则如下:共有N堆石子,已知每堆中石子的数量,并且规定好每堆石子最多可以取的石子数(最少取1颗)。

两个人轮流取子,每次只能选择N堆石子中的一堆,取一定数量的石子(最少取一个),并且取的石子数量不能多于该堆石子规定好的最多取子数,等哪个人无法取子时就表示此人输掉了游戏。

假设每次都是小王先取石子,并且游戏双方都绝对聪明,现在给你石子的堆数、每堆石子的数量和每堆石子规定的单次取子上限,请判断出小王能否获胜。

输入
第一行是一个整数T表示测试数据的组数(T<100)
每组测试数据的第一行是一个整数N(1<N<100),表示共有N堆石子,随后的N行每行表示一堆石子,这N行中每行有两个数整数m,n表示该堆石子共有m个石子,该堆石子每次最多取n个。(0<=m,n<=2^31)
输出
对于每组测试数据,输出Win表示小王可以获胜,输出Lose表示小王必然会败。
样例输入
2
1
1000 1
2
1 1
1 1
样例输出
Lose
Lose
提示
注意下面一组测试数据
2
1 1 
2 2
正确的结果应该是Win
因为小王会先从第二堆石子中取一个石子,使状态变为
1 1
1 2
这种状态下,无论对方怎么取,小王都能获胜。


#include <stdio.h>

int bashi(int n, int m){
	return n % (m+1);
}

int main(){
	int t, num, n, m, ans;
	scanf("%d", &t);
	while(t--){
		scanf("%d", &num);
		ans = 0;
		while(num--){
			scanf("%d%d", &n, &m);
			ans ^= bashi(n, m);
		}
		printf(ans ? "Win\n" : "Lose\n");
	}
	return 0;
}



取石子(三)

时间限制: 1000 ms  |  内存限制: 1000 KB
难度: 6
描述

小王喜欢与同事玩一些小游戏,今天他们选择了玩取石子。

游戏规则如下:共有N堆石子,已知每堆中石子的数量,两个人轮流取子,每次只能选择N堆石子中的一堆,取一定数量的石子(最少取一个),取过子之后,还可以将该堆石子中剩下的任意多个石子中随意选取几个放到其它的任意一堆或几堆上。等哪个人无法取子时就表示此人输掉了游戏。注意,一堆石子没有子之后,就不能再往此处放石子了。

假设每次都是小王先取石子,并且游戏双方都绝对聪明,现在给你石子的堆数、每堆石子的数量,请判断出小王能否获胜。

例如:如果最开始有4堆石子,石子个数分别为3 1 4 2,而小王想决定要先拿走第三堆石子中的两个石子(石子堆状态变为3 1 2 2),然后他可以使石子堆达到的状态有以下几种:

3 1 2 2(不再移动石子)

4 1 1 2(移动到第一堆一个)

3 2 1 2(移动到第二堆一个)

3 1 1 3(移动到第四堆一个)

5 1 0 2(全部移动到第一堆)

3 3 0 2(全部移动到第二堆)

3 1 0 4(全部移动到最后)

输入
可能有多组测试数据(测试数据组数不超过1000)
每组测试数据的第一行是一个整数,表示N(1<=N<=10)
第二行是N个整数分别表示该堆石子中石子的数量。(每堆石子数目不超过100)
当输入的N为0时,表示输入结束
输出
对于每组测试数据,输出Win表示小王可以获胜,输出Lose表示小王必然会败。
样例输入
3
2 1 3
2
1 1
0
样例输出
Win
Lose

必败态是相同石子数量的石堆数都为偶数,否则必胜。
N先手胜局 P后手胜局
剩一堆石头这N局面;
剩两堆石头 1、(a,b) a<b;则可以换成(a,a)形式,跟随后手拿法即可胜利,即N局面;
  2、(a,a) 与上相反,P局面;
    剩三堆石头(a,b,c) 先手总能转化生(m,m,0)所以N局面;
剩四堆石头 1、(a,a,b,b) 则类似两堆局面,P局面;
  2、(a,b,c,d) 总能转化成(n,n,m,m)形式,所以N局面;
    推开总的来说:如果某一个数的石子堆数为奇数,则总能转化成(n,n,m,m,……)的形式,所以N局面;
 如果局势总是(a,a,b,b,……)形式,与上相反,则P局面。



#include <stdio.h>
#include <string.h>

int arr[1001];

int main(){
	int n, ans, a;
	while(scanf("%d", &n), n){
		while(n--){
			scanf("%d", &a);
			++arr[a];
		}
		ans = 0;
		for(int i = 0; i < 1001; ++i)
			if(arr[i] & 1){
				ans = 1;
				break;
			}
		printf(ans ? "Win\n" : "Lose\n");
		memset(arr, 0, sizeof(arr));
	}
	return 0;
}



取石子 (四)

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
输入
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。
输出
输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。
样例输入
2 1
8 4
4 7
样例输出
0
1
0


#include <stdio.h>
#include <math.h>

int main(){
	int a, b, ans;
	while(scanf("%d%d", &a, &b) == 2){
		if(a > b) ans = a, a = b, b = ans;
		ans = (1 + sqrt(5.0)) / 2 * (b - a);
		printf(ans != a ? "1\n" : "0\n");
	}
	return 0;
}


取石子(五)

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述
himdd最近很想玩游戏,于是他找到acmj和他一起玩,游戏是这样的:有一堆石子,两个人轮流从其中取走一定的石子,取走最后所有石子的人为赢家,不过得遵循如下规则:
1.第一次取不能取完,至少取1颗.

2.从第二次开始,每个人取的石子数至少为1,至多为对手刚取的石子数的两倍。

himdd事先想知道自己会不会赢,你能帮帮他吗?(每次himdd先手)

输入
有多组测试数据,每组有一个整数n(2<=n<2^64);
输出
himdd会赢输出Yes,否则输出No;
样例输入
2
5
6
样例输出
No
No
Yes

斐波那契数为必败态。


#include <stdio.h>

long long n, a[100] = {2, 3};

int main(){
	int i, ans;
	for(i = 2; i != 100; ++i)
		a[i] = a[i-1] + a[i-2];
	while(scanf("%lld", &n) == 1){
		ans = 0;
		for(i = 0; i != 100; ++i)
			if(a[i] == n){ ans = 1; break; }
			else if(a[i] > n) break;
		printf(ans ? "No\n" : "Yes\n");
	}
	return 0;
}


取石子(六)

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述
最近 TopCoder PIAOYI HRDV 很无聊,于是就想了一个游戏,游戏是这样的:有 n 堆石子 , 两个人轮流从其中某一堆中任意取走一定的石子 , 最后不能取的为输家,注意:   每次只能从一堆取任意个,可以取完这堆,但不能不取。假设 PIAOYI 先取石子,请你帮他判断他是否能赢(假设他们取的过程中不发生失误 , 他们足够聪明 )。
输入
第一行输入n,代表有n组测试数据(n<=10000)
以下每组测试数据包含两行:第一行:包含一个整数m,代表本组测试数据有m(m<=1000)堆石子;
:第二行:包含m个整数Ai(Ai<=100),分别代表第i堆石子的数量。
输出
若PIAOYI赢输出“PIAOYI”,否则输出“HRDV”注意每组结果占一行。。
样例输入
3
2
1 1
3
3 8 11
2
5 10
样例输出
HRDV
HRDV
PIAOYI



#include <stdio.h>

int main(){
	int t, n, a, ans;
	scanf("%d", &t);
	while(t--){
		scanf("%d", &n);
		ans = 0;
		while(n--){
			scanf("%d", &a);
			ans ^= a;
		}
		printf(ans ? "PIAOYI\n" : "HRDV\n");
	}
	return 0;
}






你可能感兴趣的:(博弈论专题)