博弈论入坑

2024-02-17 22:38
文章标签 博弈论 入坑

本文主要是介绍博弈论入坑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

我喜欢游戏,我知道有些游戏无论我怎样努力最后的结果一定是输的,或者是无论怎样玩我都是赢得,这样的一类游戏从一开始就知道结果的游戏,一定会有一种数学方法去描述。

Nim博弈

所谓的Nim的博弈就是一种从一开始就知道胜负的游戏。这是一种两个人玩的游戏,玩家双方面对一堆硬币(或者石头或者豆粒)。(假设有k>=1堆硬币,每堆分别有 n 1 , n 2 , n 3 … … n k {n_1,n_2,n_3……n_k} n1,n2,n3nk枚硬币。游戏的目标就是取得最后一枚硬币。每个玩家只能任选一堆去拿不少于1个硬币。率先拿完所有硬币的玩家获胜。

我们来看其中的某种特殊情况:

首先是如果只有一堆,先手一下全拿完,先手必胜。第二种是有两堆,数量为n1、n2,如果n1!=n2先手的策略就是拿多的那一堆,拿完后使得两堆相等,这样重复让两堆相等那么肯定先手会赢;反之如果n1==n2先手必败。

而如果是很多堆,或者是玩法并不是拿任意>=1的硬币,而是规定硬币的个数怎么办呢???

SG函数

这里我就不给出证明过程了,直接说结论和解题方法。

首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0;

我们就可以定义一下sg(x) = mex{sg(y)|y是x的后继}这里的后继指的是存在x转换成y的方法,即对于1堆硬币来说原先有y个硬币,能通过一次move得到y枚硬币。sg(x)是对于一个游戏的子问题来说的,也就是其中一堆硬币,最后我们需要算出所有的sg值,然后进行异或运算g(G1)g(G2)…^g(Gn) = 0先手必败,不为0先手必胜。

get_sg代码

int f[maxn];      // 可以取的石子个数 idx[1~n]
int sg[maxn];     // 0 ~ n sg函数的值
int isin[maxn];   // mex{} 
void getSG(int n)
{memset(sg, 0, sizeof(sg));for(int i = 1; i <= n; i++) {memset(isin, 0, sizeof(isin));for(int j = 1; f[j] <= i; j++) {isin[sg[i-f[j]]] = 1;}for(int j = 0; j <= n; j++) {if(isin[j]==0) {    sg[i] = j;break;}}}
}

一些特例

1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1) 这其实就是巴什博奕。

2.可选步数为任意步,SG(x) = x,这其实是Nim博弈原型。

3.可选步数为一系列不连续的数,用getSG()计算,这是Nim博弈变式。

一道题

小米OJhttps://code.mi.com/problem/list/view?id=117&cid=4

这道题是在堆的数量为2,只能拿斐波那契数的一个特例。

代码:

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
const int maxn = 1e4 + 10;
int f[maxn];      // 可以取的石子个数 idx[1~n]
int sg[maxn];     // 0 ~ n sg函数的值
int isin[maxn];   // mex{} 
void get_f() {f[1] = 1;f[2] = 2;for(int i = 3; f[i-1] < maxn; i++) {f[i] = f[i-1] + f[i-2];}
}int main() 
{get_f();getSG(maxn);int num1, num2;while(cin >> num1 >> num2) {if((sg[num1]^sg[num2])==0) {cout << "Xiaobing Win" << endl;}else {cout << "Xiaoai Win" << endl;}}return 0;
}

这篇关于博弈论入坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/719194

相关文章

SpringCloud Alibaba 入坑(二)Nacos 配置中心

超详细的Java知识点路线图 文章目录 前言nacos配置中心介绍使用步骤总结 前言 SpringCloud Alibaba 入坑(一)Nacos 服务注册与发现 上篇文章介绍了nacos作为服务注册中心的用法,本文将介绍下nacos作为配置中心的用法。 nacos配置中心介绍 入坑Spring Cloud Alibaba后发现的nacos确实

【每日一题】【博弈论】【思维】会赢的! 牛客周赛 Round 58 C题 C++

牛客周赛 Round 58 C题 会赢的! 题目背景 牛客周赛 Round 58 题目描述 样例 #1 样例输入 #1 31 11 0-1 -1 样例输出 #1 NOYESPING 做题思路 首先考虑到开始位置为 ( 0 , 0 ) (0,0) (0,0)并且只能使横纵坐标递增。所以如果终点的横纵坐标为负数的情况是不可能到达的。所以平局。 第一个点: x

耶鲁大学《博弈论》公开课笔记

关于本文 该文章基于本人于当天白天看完耶鲁大学《博弈论》公开课后,于当晚记录下依然记得的白天所听内容。该文章为汇总,时间为记录一年后。 目录 关于本文2023.3.18 P103.19 P113.20 P123.21 P133.22 P143.23 P153.24 P163.25 P173.26 P183.27 P193.28 P203.29 P213.30 P223.31 P234.1

有向图游戏 SG函数【博弈论】C++

SG函数可以用来判断在一个给定的有向图游戏中,当前局面的胜负状态。 SG函数的定义如下: 设当前节点为v,那么SG(v)为当前局面的SG值。SG(v)的定义如下: - 如果当前节点v没有后继节点,则SG(v) = 0 - 如果当前节点v有若干个后继节点,分别为v1,v2,...,v_n,那么SG(v)为所有后继节点的SG值的异或和。即:SG(v) = SG(v1) XOR SG(v2) XOR

hdu 1524 A Chess Game 博弈论

题意: 两个人在一个有向五环图上面走棋子,每次只能走一步,最后谁 * 没有棋子可走就败,然后棋子可以重叠,并且有n个棋子。要求判断 * 先手的胜负。 纠结了好长时间一直在想为什么sg函数要呢么定义然后看了各种博客但是只是讲了,定义的内容却很少有讲为什么的。。。。 Description Let's design a new chess game. There are N

hdu4111 Alice and Bob 博弈论

题意:有N堆石子,每堆石子有一个数目,现有两个人博弈,每个人每次可以进行两个操作中的一个: 1、从某堆拿掉一个石子(若某堆石子为0了,那么这堆就不存在了);2、合并两堆石子 没有操作的就输。问是哪个赢 统计1的个数c,以及非1情况下的步数s,包括合并。 c为奇数,s不等于2:那么先手必胜。 s为2或者为0:c为3的倍数是先手必败。 否则的话,s为奇数时先手必胜。 首先没有1的情况下很好证明,就是

入坑爬坑必备!vot2016 配置(matlab,python)

环境ubantu18.4 +matlab2017b  A.下载预备 a.vot-toolkit  :https://github.com/votchallenge/vot-toolkit b.trax包:https://github.com/votchallenge/trax       在vot-toolkit下新建native文件夹 把trax放入 c.vot2016 :https:

博弈论--巴什博弈——HDU1846

/*巴什博弈:HDU--1846*/ # include<iostream> using namespace std; int main() {     int t;     int n,m;     cin>>t;     while(t--)     {       cin>>n>>m;       if(n%(m+1)==0) cout<<"sec

Codeforces Round 916 (Div. 3) E1. Game with Marbles(博弈论*1400)

感觉很难想。 如果你直接想的话,你就会发现有很多做法可以选择,而你根本不知道应该选哪个。 这时候可以先假设鲍勃已经取走了爱丽丝的所有的颜色的弹珠,(并且以每个颜色一个弹珠的代价)。 这时候每一项得分就是 S i = − ( b i − 1 ) S_i = -(b_i - 1) Si​=−(bi​−1)。 然后我们使得这时候爱丽丝的操作为取回弹珠,即她可以选择一种颜色的弹珠,并且直接取回,鲍勃

Codeforces Round 926 (Div. 2) C. Sasha and the Casino (博弈论*1400)

这里的意思是想让我们求得是否是能够实现不停地无上限的赚钱。 这里注意避开一个思维误区,如果你想的是前x次一直用1枚硬币然后吃第x+1次保底,那么就是错误的。你应该考虑到如果前x次里面出现了胜利呢?这时候你拿着一枚硬币根本赚不回本。 所以我们要假定:前x+1次,每一次都有可能胜利,并且每次胜利我们都需要使得自己能够赚回本金并且获得利润。 那么我们要怎么做才能够实现? 这里假设我们第i次投入