博弈游戏汇总

1、巴什博弈

一堆石子,有n个,两个人轮流取,每次至少取1个,至多取m个,拿走最后一个石子的人获胜

假设一堆石子有  n=m+1  由于一次只能取m个,无论先手取多少个,后手总能拿走剩余的,这时一定是先手负

于是找到取胜规则:

一对石子  n=(m+1)*r+s

对于先手应该先取走s个,设后手取走k个,先手再取走  m+1-k    剩余的石子个数为  (m+1)(r-1)  以后保持这样的取法,先取者获胜

总之,就是要留给对手  m+1的倍数

可以归结为:   s=0时,后手胜

s<>0时,先手胜

2、简单的石子游戏

有n堆石子,每次至少取一根,至多拿走整堆,两人轮流拿,每次限拿其中一堆,取走最后一根的获胜。

1902年获胜策略已由美国数学家C.L.Bouton分析完成,用到的是二进制和平衡状态概念。其结论是:
对于n堆石子,第i (1<=i<=n)堆石子的个数是Xi,该状态为必败状态当且仅当   X1 XOR  X2 XOR……Xn=0。

看个例子:

有4堆石子,数量分别为:7   9   12   15
二进制形式为
 0111
 1001
 1100
 1111
异或结果为:1101

1101^1001=0100=4     可以从第二堆拿走5个

1101^1100=0001=1     也可以从第三堆拿走11个

1101^1111=0010=2     或者从第四堆取走13个

比如这道题:http://www.acmicpc.sdnu.edu.cn/Problem.aspx?pid=1294

给定N堆石子,两人轮流取石子,必须先取完一堆石子才能取另一堆,而且另一堆石子的个数必须比之前取的那一堆小,每次只能取1个或者质数个石子。如果没有石子可以取了,那么他就输了。问先手是否有必胜策略。

其实对于这个游戏,我们只需要判断第一堆石子即可,也就是石子数目最少的那一堆

代码:

#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int isprime(int n){
    int s=(int)sqrt(n);
    if(n==1)  return 1;
    for(int i=2;i<=s;i++){
        if(n%i==0)
            return 0;
        break;
    }
    return 1;

}
int main(){
    int n,a[100000],x,i,j,t;
    while(cin>>n){
        for( i=0;i<n;i++)
            cin>>a[i];  //每堆石子的数目
        sort(a,a+n);
            for(j=1;j<=a[0];j++){
                if(isprime(j)&&j<=a[0])
                    a[0]=a[0]-j;
                x=0;
                for(t=0;t<n;t++)
                    x^=a[t];
                if(x==0){
                    cout<<"yes"<<endl;
                    break;
                }else
                    a[0]=a[0]+j;  //恢复石子数目
            }
            if(x!=0)
                cout<<"no"<<endl;

    }
        return 0;
}

3、Nim游戏

有n堆石子,每堆石子的数量为  x1, x2, x3,x4......xn。给定k个数a1,a2,a3,……ak  两人轮流取,每人每次只能选取一堆,

从中取出一些,每次所取的数量一定在a1,a2,a3,……ak中,拿走最后一根的人获胜。

我们可以将游戏分解,把每一堆看成是一个子游戏。

比如,有3堆石子,每堆石子的数目,为5,6,7,可以取的石子的数目是  {1,3,4}

可以找出每堆石子的所有后继状态,看成是n枚棋子在有向图上移动,甲乙双方人选一个子游戏并移动上面的棋子。

看起来状态非常多,也很复杂,所以我们需要借鉴SG函数

首先定义一个mex 运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

对于一个给定的有向无环图,关于每个顶点的SG函数定义如下:

g(x)=mex{g(y)|y是x的所有后继状态};没有出边的顶点,SG值为0,因为它的后继集合为空。

对于n枚棋子,它们对应顶点的SG值分别为:(a1,a2,……,an)再设局面  (a1,a2,……,an)时Nim游戏的一种必胜策略是  将ai变成k,那么游戏的一种必胜策略就是

把第i枚棋子移动到SG值为k的顶点上;

#include<iostream>
using namespace std;
/*输入堆数 n,每堆的石子数a[]
  输入限定选择的数目 k,   是s[]
*/
int max(int a[],int n){
    int m=0;
    for(int i=0;i<n;i++){
        if(m>a[i])
            m=a[i];
    }
    return m;
}
int main(){
    int n,a[100],i,j,s[100],k,*vis,*grund;
    while(cin>>n){
        for(i=0;i<n;i++)
            cin>>a[i];
        int size=max(a,n);
        vis=new int[size+1];
        grund=new int[size+1];
        grund[0]=0;
        cin>>k;
        for(i=0;i<k;i++)
            cin>>s[i];
        //
        for(i=1;i<=size;i++){   //i是石子的数目,a[j]是每次应当取的石子数   i-a[j]   剩余的石子数
            memset(vis,0,sizeof(vis));
            for(j=0;j<k;j++){
            if(s[j]<=i){
                vis[grund[i-s[j]]]=1;
            }
            for(int k=1;;k++){
                if(vis[k]==0)
                    grund[i]=k;
                break;
              }
            }
        }
        int x=0;
        for(i=0;i<n;i++)
            x^=grund[a[i]];
        if(x==0)   cout<<"先手胜"<<endl;
        else
                 cout<<"后手胜"<<endl;

    }
    return 0;
}

时间: 2024-10-31 19:27:33

博弈游戏汇总的相关文章

【转】ACM博弈知识汇总

博弈知识汇总 转自:http://www.cnblogs.com/kuangbin/archive/2011/08/28/2156426.html 有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可.两个人轮流从堆中取物体若干,规定最后取光物体者取胜.这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理.下面我们来分析一下要如何才能够取胜. (一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.

ACM博弈知识汇总(转)

博弈知识汇总 有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可.两个人轮流从堆中取物体若干,规定最后取光物体者取胜.这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理.下面我们来分析一下要如何才能够取胜. (一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜. 显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取

hihoCoder#: 博弈游戏&#183;Nim游戏

[题目链接]:click here~~ [题目大意]: #1163 : 博弈游戏·Nim游戏 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 今天我们要认识一对新朋友,Alice与Bob. Alice与Bob总是在进行各种各样的比试,今天他们在玩一个取石子的游戏. 在这个游戏中,Alice和Bob放置了N堆不同的石子,编号1..N,第i堆中有A[i]个石子. 每一次行动,Alice和Bob可以选择从一堆石子中取出任意数量的石子.至少取1颗,至多取出这一堆剩下的所有石

hiho一下 第四十五周 博弈游戏&#183;Nim游戏&#183;二 [ 博弈 ]

传送门 题目1 : 博弈游戏·Nim游戏·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Alice和Bob这一次准备玩一个关于硬币的游戏:N枚硬币排成一列,有的正面朝上,有的背面朝上,从左到右依次编号为1..N.现在两人轮流翻硬币,每次只能将一枚正面朝上的硬币翻过来,并且可以随自己的意愿,在一枚硬币翻转后决定要不要将该硬币左边的任意一枚硬币也翻一次(正面翻到背面或背面翻到正面).翻最后一枚正面向上的硬币的人获胜.同样的,这次游戏里面Alice仍然先手,两人均采

hiho一下 第四十四周 题目1 : 博弈游戏&#183;Nim游戏

题目1 : 博弈游戏·Nim游戏 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 今天我们要认识一对新朋友,Alice与Bob. Alice与Bob总是在进行各种各样的比试,今天他们在玩一个取石子的游戏. 在这个游戏中,Alice和Bob放置了N堆不同的石子,编号1..N,第i堆中有A[i]个石子. 每一次行动,Alice和Bob可以选择从一堆石子中取出任意数量的石子.至少取1颗,至多取出这一堆剩下的所有石子. Alice和Bob轮流行动,取走最后一个石子的人获得胜

博弈游戏

/* 博弈游戏 */ import java.util.*; class AgainstGame{ static int totalMoney;//全局 static int betNum;//全局 public static void main(String [] args){ Scanner input = new Scanner(System.in); totalMoney = 5000;//全局变量方法内初始化 System.out.println("初始余额"+totalMo

hihoCoder - #1173 : 博弈游戏&#183;Nim游戏&#183;三

#1173 : 博弈游戏·Nim游戏·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在这一次游戏中Alice和Bob决定在原来的Nim游戏上增加一条规则:每一次行动时,不仅可以选择一堆取走任意数量的石子(至少取1颗,至多取出这一堆剩下的所有石子),还可以选择将一堆石子分成两堆石子,但并不取走石子.比如说有一堆石子为k个,当Alice或者Bob行动时,可以将这一堆石子分成两堆,分别为x,y.满足x+y=k,x,y>0.那么增加了这一条规则后,在Alice总先手的

博弈游戏&#183;Nim游戏&#183;二

题目1 : 博弈游戏·Nim游戏·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Alice和Bob这一次准备玩一个关于硬币的游戏: N枚硬币排成一列,有的正面朝上,有的背面朝上,从左到右依次编号为1..N.现在两人轮流翻硬币,每次只能将一枚正面朝上的硬币翻过来,并且可以随自己的意愿,在一枚硬币翻转后决定要不要将该硬币左边的任意一枚硬币也翻一次(正面翻到背面或背面翻到正面).翻最后一枚正面向上的硬币的人获胜.同样的,这次游戏里面Alice仍然先手,两人均采取最优

蓝桥杯——说好的进阶之取数博弈游戏(动态规划实现)

今盒子里有n个小球,A.B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断. 我们约定: 每个人从盒子中取出的球的数目必须是:1,3,7或者8个. 轮到某一方取球时不能弃权! A先取球,然后双方交替取球,直到取完. 被迫拿到最后一个球的一方为负方(输方) 请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A是否能赢? 程序运行时,从标准输入获得数据,其格式如下: 先是一个整数n(n<100),表示接下来有n个整数.