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