zoukankan      html  css  js  c++  java
  • 《博弈论》

    尼姆博弈:

    一:给定n堆石子,每次可以从一堆中取任意数量个,最后一个取完的获胜。

    二:给定n堆石子,每次可以从一堆中取最多k个,最后一个取完的获胜。

    三:给定n堆石子,每次可以选最多k堆,每堆可以取任意数量个,最后一个取完的获胜。

    Solution:

    一:这是最经典的一种尼姆博弈,先手必胜态为所有堆石子数异或后答案不为0.否则为必败态。

    二: 对每堆的石子数模上(k + 1),就变成了经典的尼姆博弈类型。

    三:这个问题又被称为nimk博弈,我们把每堆石头都表示成二进制,从每个二进制位去考虑。

    统计每个二进制位上1的个数,如果满足每个二进制位上1的个数都可以 % (k + 1) = 0.那么先手必败。

    反之,先手必胜。

    巴什博弈:

    有一堆n个石子,每次最多可以取k个,最后一个取完的获胜。

    Solution:

    如果n % (k + 1) == 0,那么后手只要每次和先手的数量凑成k + 1即可,那么后手必胜。

    反之,先手先加上取模后的余数,然后就满足了 n % (k + 1) == 0的情况,此时先手变后手了,那么先手必胜。

    威佐夫博弈:

    给出两堆石子,有两种操作:1:从一堆中取任意个石子。2:从两堆中取相同数量的石子。最后一个取完的获胜。

    结论:

    黄金分割比:1.618 = (sqrt(5)+ 1) /  2 。//精度高

    设两堆石子数为a,b。如果满足a = (a - b) * 1.618,先手必败,反之必胜。

    https://www.cnblogs.com/csushl/p/10331498.html

    HDU1079:Calendar Game

    可以发现一共的日期并不多,所以考虑dp转移必胜态即可。其实这里也有规律可以找规律。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    const int N = 2e5 + 5;
    const int M = 1e3 + 5;
    const double eps = 1e-10;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read() {
        int f = 1;LL x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    bool dp[105][15][35];
    int a[15];
    int cal(int year) {
        if(year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) return 29;
        return 28;
    } 
    void init() {
        a[1] = 31,a[2] = 0,a[3] = 31,a[4] = 30,a[5] = 31,a[6] = 30,a[7] = 31,a[8] = 31,a[9] = 30,a[10] = 31,a[11] = 30,a[12] = 31;
        dp[101][11][3] = 1;
        dp[101][11][2] = 0;
        dp[101][11][1] = 1;
        for(int i = 2001;i >= 1900;--i) {
            int L = 1,r = 12;
            if(i == 2001) r = 10;
            for(int j = r;j >= L;--j) {
                int ll = 1,rr = a[j];
                if(j == 2) rr = cal(i);
                for(int k = rr;k >= ll;--k) {
                    int tag = 1;
                    if(k != rr) tag &= dp[i - 1900][j][k + 1];
                    else {
                        if(j == 12) tag &= dp[i - 1900 + 1][1][1]; 
                        else tag &= dp[i - 1900][j + 1][1];
                    }
                    if(i == 2001 && j == 10 && k >= 5) tag &= 1;
                    else {
                        if(j == 12) tag &= dp[i - 1900 + 1][1][k];
                        else {
                            if(j == 1) {
                                int nxt = cal(i);
                                if(nxt >= k) tag &= dp[i - 1900][j + 1][k];
                            }
                            else {
                                if(a[j + 1] >= k) tag &= dp[i - 1900][j + 1][k];
                            }
                        }
                    }
                    if(tag == 0) dp[i - 1900][j][k] = 1; 
                }
            }
    
        }
    }
    void solve() {
        int x,y,z;scanf("%d %d %d",&x,&y,&z);
        printf("%s
    ",dp[x - 1900][y][z] ? "YES" : "NO");
    }
    int main() {    
        init();
        int ca;scanf("%d",&ca);
        while(ca--) {
            solve();
        }
        system("pause");
        return 0;
    }
    View Code 

    HDU1525:Euclid's Game

    我们可以发现对于只能减去一倍的情况,是没有什么好说的只能老实去减。

    然后就是对于多倍的情况,可以发现的是,有两个种操作,一种全部减去,先手变后手,另一种减去k - 1倍,那么下一个人只能减去剩下的一倍,先手依旧变先手。

    所以对于多倍我们可以操作成对自己有利的情况,那么,很显然能决定答案的,就是最后一个多倍的情况。也就是说谁能先操作最后一个多倍,那么谁就能赢。

    然后因为对于多倍我们可以决定下一次的先后手情况,那么很显然就说明第一个操作多倍的人,可以让自己也先操作下一个多倍。

    那么我们就可以知道了,谁先操作第一个多倍,谁就可以永远第一个操作所有的多倍,也就可以获胜。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    const int N = 2e5 + 5;
    const int M = 1e3 + 5;
    const double eps = 1e-10;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read() {
        int f = 1;LL x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    void solve() {
        int x,y;
        while(scanf("%d %d",&x,&y),x != 0 || y != 0) {
            int ta = 1;
            if(x < y) swap(x,y);
            if(x % y == 0) {printf("Stan wins
    ");continue;}
            int g = 0;
            while(1) {
                if(x < y) swap(x,y);
                if(x % y == 0) {printf("%s
    ",g == 0 ? "Stan wins" : "Ollie wins");break;}
                int k = x / y;
                if(k == 1) x -= y,g ^= 1;
                else {
                    if(g == 0) {printf("Stan wins
    ");break;}
                    else {printf("Ollie wins
    ");break;}
                }
            }
        }
    }
    int main() {    
        solve();
        system("pause");
        return 0;
    }
    View Code

    HDU1564:Play a game

    猜测了一下只和总个数有关,结果就是这样。

    模拟了一下发现,不管怎么样先后手想去改变输赢情况,即棋子奇偶数,隔出去的数量总是偶数个,不会改变原来的奇偶情况。

    所以只和原来的奇偶数有关。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    const int N = 2e5 + 5;
    const int M = 1e3 + 5;
    const double eps = 1e-10;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read() {
        int f = 1;LL x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    void solve() {
        int n;
        while(scanf("%d",&n),n != 0) {
            printf("%s
    ",n % 2 == 0 ? "8600" : "ailyanlu");
        }
    }
    int main() {    
        solve();
        system("pause");
        return 0;
    }
    View Code

    HDU1846:Brave Game

    巴什博弈的模型。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    const int N = 2e5 + 5;
    const int M = 1e3 + 5;
    const double eps = 1e-10;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read() {
        int f = 1;LL x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    void solve() {
        int n,m;scanf("%d %d",&n,&m);
        if(m >= n) printf("first
    ");
        else {
            if(n % (m + 1) == 0) printf("second
    ");
            else printf("first
    ");
        }
    }
    int main() {    
        int ca;scanf("%d",&ca);
        while(ca--) {
            solve();
        }
        system("pause");
        return 0;
    }
    View Code

    HDU1847:Good Luck in CET-4 Everybody!

    SG板子题。SG函数求一下即可。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    const int N = 1e4 + 5;
    const int M = 1e3 + 5;
    const double eps = 1e-10;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read() {
        int f = 1;LL x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    bool S[N];
    int SG[N];
    int f[10];
    void init(int x) {
        memset(SG,0,sizeof(SG));
        for(int i = 1;i <= x;++i) {
            memset(S,0,sizeof(S));
            for(int j = 0;j <= 9 && f[j] <= i;++j) S[SG[i - f[j]]] = 1;
            for(int j = 0;;++j) if(!S[j]) {SG[i] = j;break;}
        }
    }
    void solve() {
        int n;
        f[0] = 1;
        for(int i = 1;i <= 9;++i) f[i] = f[i - 1] * 2;
        while(~scanf("%d",&n)) {
            init(n);
            printf("%s
    ",SG[n] == 0 ? "Cici" : "Kiki");
        }
    }
    int main() {    
        solve();
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    JAVA开源B2C系统
    在IDEA中将SpringBoot项目打包成jar包的方法
    国外的开源项目Shopizer部署问题
    SpringBoot集成RabbitMQ
    隐藏网页中DIV和DOM的各种方法
    SpringCloud之网关 Zuul(四)
    SpringCloud之声明式服务调用 Feign(三)
    SpringCloud之实现客户端的负载均衡Ribbon(二)
    SpringCloud之服务注册与发现Eureka(一)
    IntelliJ IDEA maven springmvc+shiro简单项目
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15195848.html
Copyright © 2011-2022 走看看