三种简单的博弈

博弈问题:(1)、对于必胜状态,一定有一个后继是必败的;

                  (2),对于必败状态,它的所有后继是必胜的;

巴什博奕:

1、  本游戏是一个二人游戏;
2、  有一堆石子一共有n个;
3、  两人轮流进行;
4、  每走一步可以取走1…m个石子;
5、  最先取光石子的一方为胜;

如果游戏的双方使用的都是最优策略,请输出哪个人能赢。

巴什博奕可以用SG函数来推导,但是时间复杂度太高。可以直接将其转化为n = k*(m+1) + r; 如果 r > 0, 则先手一定会赢

简单的巴什博奕题目 hdu1846;

SG函数能过

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<string>
#define MAX 1010
#define INF INT_MAX
#define eps 1e-6
#define REP(i,n) for (int i=0; i<(n); i++)
#define FOR(i,s,t) for (int i=(s); i<=(t); i++)

using namespace std;

int vis[MAX],sg[MAX];

int main(){
	int T,n,m;
	scanf("%d", &T);
	sg[0] = 0;
	while (T--){
		scanf("%d%d",&n,&m);
		for (int i = 1; i<=n; i++){
			memset(vis,0,sizeof(vis));
			for (int j=1; j<=m&&j<=i; j++){
				vis[sg[i-j]] = 1;
			}
			for (int j=0; ; j++){
				if (!vis[j]){
					sg[i] = j;
					break;
				}
			}
		}
		if (sg[n] == 0) printf("second\n");
		else printf("first\n");
	}
	return 0;
}
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<string>
#define MAX 1000
#define INF INT_MAX
#define eps 1e-6
#define REP(i,n) for (int i=0; i<(n); i++)
#define FOR(i,s,t) for (int i=(s); i<=(t); i++)

using namespace std;

int main(){
    int T,n,m;
    scanf("%d", &T);
    while (T--){
        scanf("%d%d",&n,&m);
        if (n % (m+1) == 0){
            printf("second\n");
        } 
        else printf("first\n");
    }
    return 0;
}

威佐夫博奕:

问题描述:有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

判断当前状态必败状态的依据:<a,b>为必败态,当且仅当a = (i*(1+sqrt(5) / 2)(向下取整) ,b = a + i;

poj1067简单的威佐夫博奕;

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<string>
#define ll long long
#define MAX 1000
#define INF INT_MAX
#define eps 1e-8

using namespace std;

int main(){
	int a,b;
	while (scanf("%d%d",&a,&b) != EOF){
		if (a > b) swap(a,b);
		int i = b - a;
		if ((int)((i*(1.0 + sqrt(5.0)) / 2.0)) == a){
			printf("0\n");
		}
		else printf("1\n");
	}
	return 0;
}
尼姆博奕:

问题描述:有n堆火柴,数量分别为a,b,c,d,,,,每次可以从任意一堆中至少拿走一根,也可以去全部拿走,但不能从多根火柴中同时拿。无法拿火柴的游戏者输。

解法:L.Bouton定理:如果a xor b xor c xor d ,,, = 0,则先受败,否则先手胜。

简单的尼姆博奕 poj 2234;

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<string>
#define MAX 1010
#define INF INT_MAX
#define eps 1e-6
#define REP(i,n) for (int i=0; i<(n); i++)
#define FOR(i,s,t) for (int i=(s); i<=(t); i++)

using namespace std;

int main(){
	int M,a;
	while(scanf("%d",&M) != EOF){
		int res = 0;
		for (int i=0; i<M; i++){
			scanf("%d",&a);
			res ^= a;
		}
		if (res == 0) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值