博弈论-巴什博奕

问题描述:

有一堆物品,共n个,两人轮流从这堆物品中取,规定每次至少取一个,至多m个,获胜条件分为两种,分别是最后取光者胜或者是最后取光者败。

情形一:最后取光者胜

分析:

            若n=m+1,则无论先手取走多少,后手一定可以一次性取走剩下的全部物品,这时后手胜;

            若n=(m+1)*r+s,且s<=m,r为任意自然数,此时先手只要先取s个,那么后手取k个(k<=m),然后先手再取m+1-k个,也就是某一组m+1个中的剩下的物品,这时候总数成为(m+1)*(r-1),所以局面成为(m+1)的任意倍,那么在接下来的游戏过程中,无论后手取多少,先手总可以取走对应的数目从而使得总数恢复到(m+1)的整数倍,一直这样下去,先手必胜。

 

因此,我们总结一下,在这样的游戏规则下,求k=n%(m+1),若k不为0,则此时相当于k就是上文中提到的s,所以先手必胜,若k为0呢,则先手面临的就是当前总数为(m+1)的整数倍的情形,所以必败。

 

可能我们会想:为什么一定是m+1的整数倍呢?就因为我们是从n=m+1开始分析的吗?当然不是这样的,因为以(m+1)的整数倍作为判断标准可以穷尽全部情况,假设我们修改一下上文中的公式,改成:n=(m+2)*r+s(s<=m),我们可以提取出一个r来,变成:n=(m+1)*r+s+r,所以呢,此时我们完全可以将s+r整体当做新的s,或者把它称作s',当然,此时s'很有可能已经超过了m+1,但我们就可以提取出其中(m+1)的部分来,与前面的式子合并,最后就变成了n=(m+1)*(r+1)+s'-(m+1),这就又归结到了最初的那个公式当中,所以千变万化逃不出开始的公式,也就是穷尽了所有的情况~

情形二:最后取光者败

求k=(n-1)%(m+1),若k=0,则后手胜,若k!=0,则先手胜。

 

 

 

 


 

1.取石子(一)

代码:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 1000
#define MAX 1<<30
#define V vector<int>

using namespace std;

int main(){
//    freopen("D:\\CbWorkspace\\博弈论\\取石子(一).txt","r",stdin);
    int T,n,m;
    I("%d",&T);
    while(T--){
        I("%d%d",&n,&m);
        int k=n%(m+1);
        if(k) puts("Win");
        else  puts("Lose");
    }
    return 0;
}
View Code

理解:

直接套用k=n%(m+1)的公式,如果k==0,后手胜,否则先手胜。


 2.Public Sale

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 1000
#define MAX 1<<30
#define V vector<int>

using namespace std;

int main(){
    freopen("D:\\CbWorkspace\\博弈论\\Public sale.txt","r",stdin);
    int m,n;
    while(~scanf("%d%d",&n,&m)){
        int k=n%(m+1);
        if(n<=m){
            while(k<=m){
                O("%d",k);
                if(k!=m) O(" ");
                k++;
            }
            puts("");
        }else{
            if(k) O("%d\n",k);
            else puts("none");
        }
    }
    return 0;
}
View Code

理解:

经典模型的变形


 

posted @ 2018-02-13 15:05  TQCAI  阅读(729)  评论(0编辑  收藏  举报