zoukankan      html  css  js  c++  java
  • 博弈论入门

    基本概念

    • 先手必胜状:先手可以从这个状态走到某一个必败态。
    • 先手必败态:先手走不到任何一个必败态。
    • 也就是说先手必胜态,那么先手一定能采取某些操作,让后手面对必败态。如果是先手必败态,无论先手怎么操作,都无法让后手面对必败态。

    基本模型

    巴什博弈

    假设一堆石子有n个,每次最多取m个,甲乙两个玩家轮流取石子,最后把石子取完的人获胜,保证甲乙每一步的决策都是最优的,请问给定n和m,问甲胜还是乙胜。

    假设, (n = m + 1)​,那么后手必胜。

    (n = (m + 1) imes r + s)​, 如果 (s = 0),先手每次取 (x) 个,后手只要每次 ((m + 1 - x)) 个即可,后手必胜,

    如果 (s) 不等于 (0), 先手第一次取 (s) 个,后手每次取 (x) 个,先手只要每次 ((m + 1 - x)) 个即可,先手必胜,

    所以只需要讨论 (s) 是否为 (0)

    nim游戏

    玩家: 2人;

    道具: (n) 堆石子,每堆石子的数量分别为 (x_1, x_2, …… x_n)

    规则:

    1. 游戏双方轮流取石子;
    2. 每人每次选一堆石子,并从中取走若干颗石子(至少取 (1) 颗);
    3. 所有石子被取完,则游戏结束;
    4. 如果轮到某人取时已没有石子可取,那此人算负。

    假如两个游戏玩家都非常聪明,问谁胜谁负?

    结论:

    (x_1 oplus x_2 …… oplus x_n = 0) 则先手必败,反之必胜。

    证明:

    先考虑它的子问题。

    (n = 1)​ 时,显然是先手必胜的,可以理解为 $S_1 $​ ^ (0 = S)

    (n = 2)​时,假设一堆与另一堆相等,无论先手取什么,后手跟着取就好了,是后手必胜,可以理解为

    (s_1) ^ (s_2 = 0)​​。

    假设一堆与另一堆不相等,先手就直接在多的一堆取两堆的差值,这样又变成了上一种情况,不过现在是先手必胜,可以理解为 (s_1)​ ^ (s_2 = s)​​。

    接下来将堆数,扩展到 (n)

    最终获胜的式子为 $ 0(​​ ^ 0 ^ 0 ^ 0 = 0, 而最初的状态为)s_1$​ ^ $ s_2$​ ^ (s_3) ^ (s_4= s)​。

    …………………………

    /*
    Date:
    Source:
    konwledge:
    */
    #include <iostream>
    #include <cstdio>
    #define orz cout << "AK IOI" << "
    "
    
    using namespace std;
    const int maxn = 1e4 + 10;
    
    inline int read()
    {
    	int f = 0, x = 0; char ch = getchar();
    	while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    	while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
    	return f ? -x : x;
    }
    inline void print(int X)
    {
    	if(X < 0) X = ~(X - 1), putchar('-');
    	if(X > 9) print(X / 10);
    	putchar(X % 10 ^ '0');
    }
    int T, n;
    int main()
    {
    	//freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
    	T = read();
    	while(T--)
    	{
    		n = read();
    		int res = 0;
    		for(int i = 1; i <= n; i++) 
    		{
    			int x = read();
    			res ^= x;
    		}
    		if(res == 0) puts("No");
    		else puts("Yes");
    	}
    	return 0;
    }
    

    威佐夫博弈

    有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

    结论:

    当两堆石子各有 (n)​ 和 (m)​​ 个,设 (n < m)​。

    那么先手必败,当且仅当 ((m - n) imes frac {sqrt5 + 1}2 = n)​。

    好的,我并不会证明。

    /*
    Date:
    Source:
    konwledge:
    */
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #define orz cout << "AK IOI" << "
    "
    #define int long long
    
    using namespace std;
    
    inline int read()
    {
    	int f = 0, x = 0; char ch = getchar();
    	while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    	while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
    	return f ? -x : x;
    }
    inline void print(int X)
    {
    	if(X < 0) X = ~(X - 1), putchar('-');
    	if(X > 9) print(X / 10);
    	putchar(X % 10 + '0');
    }
    int a, b;
    signed main()
    {
        a = read(), b = read();
        if(a > b) swap(a, b); 
        int c = b - a;
        int d = (sqrt(5) + 1) / 2 * c;
        if(a == d) puts("0");
    	else puts("1");
        return 0;
    }
    

    SG函数

    mex 运算

    定义(mes(s)) 为不属于集合 (s)​​ 的最小非负整数解。

    SG 函数

    设对于每个节点 (x)​, 设从 (x)​ 出发有 (k)​ 条有向边分别到达节点(y_1,y_2,…,y_k)​ 。

    定义 (SG(x))​ 函数为后继节点 (y_1,y_2,…,y_k)​的SG函数值构成的集合再执行 mex运算的结果。

    特别的, 整个有向图的 (SG)​ 函数被定义为有向图起点 (s)(SG) 函数值, 即(SG(G)=SG(s))

    有向图终点的 (SG) 函数为 (0)

    结论:

    先手必败, 则该局面对应 (SG)​ 函数 (=0)​,反之必胜。

    //f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理
    //SG[]:0~n的SG函数值
    //S[]:为x后继状态的集合
    int f[N],SG[MAXN],S[MAXN];
    void  getSG(int n){
        int i,j;
        memset(SG,0,sizeof(SG));
        //因为SG[0]始终等于0,所以i从1开始
        for(i = 1; i <= n; i++){
            //每一次都要将上一状态 的 后继集合 重置
            memset(S,0,sizeof(S));
            for(j = 0; f[j] <= i && j <= N; j++)
                S[SG[i-f[j]]] = 1;  //将后继状态的SG函数值进行标记
            for(j = 0;; j++) if(!S[j]){   //查询当前后继状态SG值中最小的非零值
                SG[i] = j;
                break;
            }
        }
    }
    

    挖个坑吧!!!

  • 相关阅读:
    微前端的那些事儿
    网络是怎样连接的 作者户根勤 交流论坛
    数据结构与算法学习
    cpu读取指令时读取的长度
    小程序开发
    npm 安装 chromedriver 失败的解决办法
    Git:代码冲突常见解决方法
    Android通过Chrome Inspect调试WebView的H5 App出现空白页面的解决方法(不需要FQ)
    pm2
    多媒体技术及应用
  • 原文地址:https://www.cnblogs.com/yangchengcheng/p/15243309.html
Copyright © 2011-2022 走看看