博弈论的三个小游戏: Bash游戏 威佐夫游戏 Nim游戏

来源:互联网 发布:综艺节目推荐 知乎 编辑:程序博客网 时间:2024/05/16 18:52

Bash游戏

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1066

游戏规则:有一堆石子一共N个,两人轮流拿,最少拿1个,最多拿K个,最后拿完石子的获胜。

证明:
如果N % (k+1) == 0,B必胜,
否则A必胜

代码如下:

#include <iostream>#include <algorithm>#include <cstring>#include <stdio.h>#include <string>#include <cmath>#define ll long long#define mem(name,value) memset(name,value,sizeof(name))using namespace std;const int maxn = 105;int dp[maxn][maxn];int main(){    int t;    cin >> t;    while(t--){        int n,k;        cin >> n >> k;        if(n % (k+1) == 0) cout << "B" <<endl;        else cout << "A" <<endl;    }    return 0;}

威佐夫

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1072

游戏规则:有两堆石子,两个人轮流从中取石子,可以从其中一堆中取不少于一个的石子或者从两堆石子中取相同的石子,最后把石子取完的人获胜。

证明:
后手胜利的情况为:
(1, 2)
(3, 5)
(4, 7)
(6, 10)
(8, 13)
(9, 15)
(11, 18)
(12, 20)
。。。。。。
令 m = (1 + sqrt(5))/2 (黄金分割数+1 = 1.618)
观察发现每队整数之差为k,ak = [k*m] , bk = ak+k。
因此只要判断 [(bk-ak)*m] 是否== ak就可以了

代码如下:

#include <iostream>#include <algorithm>#include <cstring>#include <stdio.h>#include <string>#include <cmath>#define ll long long#define mem(name,value) memset(name,value,sizeof(name))using namespace std;const int maxn = 105;int dp[maxn][maxn];int ak, bk;double x;int main() {    int n;    cin >> n;    x = (1 + sqrt(5.0)) / 2;    for(int i=0;i<n;i++){        scanf("%d %d", &ak, &bk);        if(ak > bk) swap(ak,bk);        int k = bk - ak;        if(ak == (int)(k * x)) printf("B\n");        else printf("A\n");    }}

Nim游戏

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1069

游戏规则:有N堆石子。A B两个人轮流拿,A先拿。每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。假设A B都非常聪明,拿石子的过程中不会出现失误。给出N及每堆石子的数量,问最后谁能赢得比赛。
例如:3堆石子,每堆1颗。A拿1颗,B拿1颗,此时还剩1堆,所以A可以拿到最后1颗石子。

此题有个很奇妙的公式就是 如果n堆石子的个数满足 A0^A1^A2……An == 0则B获胜,否则A获胜。

证明:
如果 A0^A1^A2……An == K!= 0,n堆石子中一定存在一堆石子m,Am的最高位>= k,那么A一定可以从A堆中取出一定的石子使得K == 0。
而当K == 0且游戏没结束时,无论B取出多少个石子,K总!= 0,故A必胜。
如果A0^A1^A2……An == 0时,由于A先取,由上述可知B必胜。

代码如下:

#include <iostream>#include <algorithm>#include <cstring>#include <stdio.h>#include <string>#include <cmath>#define ll long long#define mem(name,value) memset(name,value,sizeof(name))using namespace std;const int maxn = 105;int dp[maxn][maxn];int main(){    int n;    cin >> n;    int x;    int sum = 0;    for(int i=0;i<n;i++){        scanf("%d",&x);        sum ^= x;    }    if(sum == 0) cout << "B" <<endl;    else cout << "A" << endl;    return 0;}
0 0
原创粉丝点击