三种简单的博弈

来源:互联网 发布:最好用的纹身单片机 编辑:程序博客网 时间:2024/05/16 10:37

博弈问题:(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-8using 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;} 



0 0
原创粉丝点击