• 博弈论


    推荐博客:

    常见的几种组合博弈:http://www.cnblogs.com/ECJTUACM-873284962/p/6398385.html

    SG函数与SG定理:https://www.cnblogs.com/ECJTUACM-873284962/p/6921829.html

    SG函数:https://blog.csdn.net/kamisama123/article/details/77649118

    例题:

    1.hdoj1846 Brave Game

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=1846

    题意:一堆石子,两个人轮流取,要求每次取的个数在$(1-m)$内。问谁获胜。

    分析:巴什博弈模板。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int t,n,m; scanf("%d",&t);
     5     while (t--){
     6         scanf("%d%d",&n,&m);
     7         if (n%(m+1)==0) printf("second
    "); else printf("first
    ");
     8     }
     9     return 0;
    10 }
    hdoj1846

    2.hdoj2149 Public Sale

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=2149

    题意:物品初始价值为0,两个人轮流加价,范围为$1-m$,当价值$ge n$时,获胜。问先手第一次加价多少时,一定获胜。

    分析:巴什博弈。保证先手必胜的状态下输出先手应该选择的数值。注意$n le m$。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int n,m;
     5     while (~scanf("%d%d",&n,&m)){
     6         if (m>=n){
     7             for (int i=n;i<m;i++) printf("%d ",i);
     8             printf("%d
    ",m);
     9             continue;
    10         }
    11         if (n%(m+1)==0){
    12             printf("none
    ");
    13             continue;
    14         }
    15         printf("%d
    ",n%(m+1));
    16     }
    17     return 0;
    18 }
    hdoj2149

    3.hdoj2188 选拔志愿者

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=2188

    题意:物品初始价值为0,两个人轮流加价,范围为$1-m$,当价值$ge n$时,获胜。问谁获胜。

    分析:巴什博弈。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int t,n,m; cin >> t;
     5     while (t--){
     6         cin >> n >> m;
     7         if (n%(m+1)==0) cout << "Rabbit
    ";
     8         else cout << "Grass
    ";
     9     }
    10     return 0;
    11 }
    hdoj2188

    4.hdoj4767 Stone

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=4764

    题意:两个人轮流写数,要求后一个数比前一个数大,且范围在$1-m$,第一个写下$geq n$的人输。

    分析:巴什博弈。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int n,m;
     5     while (cin >> n >> m){
     6         if (n+m==0) break;
     7         if ((n-1)%(m+1)==0) cout << "Jiang
    ";
     8         else cout << "Tang
    ";
     9     }
    10     return 0;
    11 }
    hdoj4767

    5.hdoj 2147 kiki's game

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=2147

    题意:有一个棋盘,两个人轮流操作,每次可以走左,下,左下三个方向,不可操作的人输。问先手的输赢。

    分析:用必败,必胜态分析。

    代码:

    hdoj2147

     6.hdoj2516 取石子游戏

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=2516

    题意:有一堆石子,两人轮流取,先手第1次可以取任意多个,但不能全部取完。以后每次取的石子数不能超过上次取子数的2倍。取完的人获胜。

    分析:斐波那契博弈。https://blog.csdn.net/acm_cxlove/article/details/7835016

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll fib[50];
     5 int main(){
     6     fib[1]=1; fib[2]=2;
     7     for (int i=3;i<50;i++) fib[i]=fib[i-1]+fib[i-2];
     8     ll n;
     9     while (cin >> n && n){
    10         int f=1;
    11         for (int i=1;i<50;i++)
    12             if (fib[i]==n){
    13                 printf("Second win
    ");
    14                 f=0;
    15             }
    16         if (f) printf("First win
    ");
    17     }
    18     return 0;
    19 }
    hdoj2516

     7.hdoj1527 取石子游戏

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=1527

    题意:有两堆石子,两个人轮流取,每次可以在一堆中取任意个,也可以在两堆中取同样多个。取完为胜,问先手的输赢。

    分析:威佐夫博弈模板。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int a,b;
     5     while (~scanf("%d%d",&a,&b)){
     6         if (a>b) swap(a,b);
     7         double k=(sqrt(5.0)-1.0)/2.0;
     8         int j=a*k;
     9         if (a!=j*(int)(k+1)) j++;
    10         if (a+j==b) cout << "0
    "; else cout << "1
    ";
    11     }
    12 } 
    hdoj1527

     8.hdoj2177 取(2堆)石子游戏

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=2177

    题意:有两堆石子,两个人轮流取,每次可以在一堆中取任意个,也可以在两堆中取同样多个。取完为胜,问若先手获胜第一次需要取多少。

    分析:威佐夫博弈。输出第一次的方案,性质:对于每一个自然数都属于一个奇异局势。一对自然数的差值对应一个奇异局势。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int n,m;  double tmp=(sqrt(5)+1)/2.0;
     5     while (~scanf("%d%d",&n,&m)){
     6         if (n+m==0) break;
     7         if (n>m) swap(n,m);
     8         int b=(m-n)*tmp;
     9         if (n==b) printf("0
    ");
    10         else{
    11             printf("1
    ");
    12             if (b<=n) printf("%d %d
    ",b,b+m-n);
    13             if (n==0 || m==0) printf("0 0
    ");
    14             for (int i=1;i<=m;i++){
    15                 b=i*tmp;
    16                 if (b==tmp) continue;
    17                 if (b==n && b+i<=m) printf("%d %d
    ",b,b+i);
    18                 else if (b+i==n && b<=m) printf("%d %d
    ",b,b+i);
    19                 else if (b<=n && b+i==m) printf("%d %d
    ",b,b+i);
    20                 else if (b+i<=n && b==m) printf("%d %d
    ",b,b+i);
    21             }
    22         }
    23     }
    24     return 0;
    25 } 
    hdoj2177

    9.hdoj1850 Being a Good Boy in Spring Festival

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=1850

    题意:n堆石子,每次可以取一堆中的任意个,问先手获胜的前提下第一次取的方案数有多少。

    分析:nim博弈。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int a[150];
     4 int main(){
     5     int n;
     6     while (~scanf("%d",&n)){
     7         if (n==0) break;
     8         int flag=0;
     9         for (int i=0;i<n;i++){
    10             cin >> a[i];
    11             flag^=a[i];
    12         }
    13         int ans=0;
    14         for (int i=0;i<n;i++){
    15             int tmp=flag^a[i];
    16             if (tmp<a[i]) ans++;
    17         }
    18         printf("%d
    ",ans);
    19     }
    20     return 0;
    21 } 
    hdoj1850

    10.hdoj1847 Good Luck in CET-4 Everybody!

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=1847

    题意:一堆石子,两个人轮流取,每次可以取2的幂次方个。问先手是否可以获胜。

    分析:SG打表。

    代码:

     1 #include<iostream> 
     2 using namespace std; 
     3 int main() { 
     4     int n; 
     5     while(scanf("%d",&n)==1) { 
     6         if(n%3==0) 
     7             cout<<"Cici"<<endl; 
     8         else 
     9             cout<<"Kiki"<<endl; 
    10     } 
    11     return 0; 
    12 } 
    hdoj187

    11.hdoj1848 Fibonacci again and again

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=1848

    题意:有三堆石子,两个人轮流取,每次要求取的个数为斐波那契值。问谁会赢。

    分析:三堆石子的nim游戏。用SG函数处理,最后取异或和即好。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1010;
    int f[maxn],sg[maxn],S[maxn];
    void init(){
        f[1]=1; f[2]=2;
        int tot=2;
        for (int i=3;i;i++){
            tot++;
            f[i]=f[i-1]+f[i-2];
            if (f[i]>maxn) break;
        }
        //SG
        memset(sg,0,sizeof(sg));
        for (int i=1;i<maxn;i++){
            memset(S,0,sizeof(S)); //标记后继状态 
            for (int j=1;f[j]<=i && j<tot;j++)
                S[sg[i-f[j]]]=1;
            for (int j=0;;j++)
                if (!S[j]){sg[i]=j;break;}
        }
        //for (int i=0;i<=20;i++) cout << sg[i] << endl;
    }
    int main(){
        int n,m,k;
        init();
        while (~scanf("%d%d%d",&n,&m,&k)){
            if (n+m+k==0) break;
            if (sg[n]^sg[m]^sg[k]) printf("Fibo
    ");
            else printf("Nacci
    "); 
        }
        return 0;
    } 
    hdoj1848
  • 相关阅读:
    接口
    java基础
    java的反射
    按照字典序打印所有的字符串
    求幂的问题
    时间复杂度与空间复杂度
    孩子们的游戏(圆圈中最后剩下的数)
    约瑟夫环问题
    翻转单词顺序列
    复杂链表的复制
  • 原文地址:https://www.cnblogs.com/changer-qyz/p/10649858.html
Copyright © 2020-2023  润新知