博弈论学习笔记

决定近段时间复习一下博弈论顺便写点笔记。

大佬博客:几种常见博弈模型https://blog.csdn.net/wr132/article/details/51213331

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

无敌的博弈总结https://blog.csdn.net/acm_cxlove/article/details/7854526

 

常见博弈模型

首先要清楚博弈论的基础知识概念(必胜必败态,多堆游戏,公平组合游戏,有向图游戏),然后了解几种常见的博弈模型,其中中比较常见的应该就是巴什博弈和尼姆博弈了。把一些题目转换为经典的博弈论模型能够快速地找到规律解决问题。

巴什博弈:只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个,最后取光者得胜。n%(m+1)=0,是必先手败的局势。

威佐夫博奕:有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。奇异局势:ak =[k(1+√5)/2],bk= ak + k先手必败。

尼姆博弈:有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。(a,b,c)是必败态等价于a^b^c=0。

 HDU-2149

巴什博弈裸题,问是否先手必胜,是的话输出先手第一次出手的必胜策略。m%(n+1)不为0先手必胜,必胜策略分两种如果m<=n那么先手就可以一次胜利,否则就第一次就要出m%(n+1)。

#include<bits/stdc++.h>
using namespace std;int main()
{int m,n;while (scanf("%d%d",&m,&n)==2) {if (m%(n+1)==0) {puts("none"); continue;}if (m<=n) {printf("%d",m); for (int i=m+1;i<=n;i++) printf(" %d",i);} else {printf("%d",m%(n+1));}puts("");}return 0;
}
View Code

POJ-1067

威佐夫博奕裸题,只有奇异局势的时候是必败态,奇异局势的公式为 ak =[k(1+√5)/2],bk= ak + k 。我们怎么判断呢?用bk-ak得到k,然后用这个k计算得到ak看看和原ak是否相等。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;int main()
{int n,m;while (scanf("%d%d",&n,&m)==2) {if (m>n) swap(n,m);int k=n-m;int tmp=floor(k*(1.0+sqrt(5.0))/2);if (tmp==m) puts("0"); else puts("1");}return 0;
}
View Code

HDU-1847

巴什博弈变形。我们观察到3是一个先手必败点,所以大家都避免走到3,但是只要有一个人避免了必败点他就可以通过对方出的数凑成3的倍数让对方必败。所以n是3的倍数时候先手必败否则先手必胜。

#include<bits/stdc++.h>
using namespace std;int main()
{int n;while (scanf("%d",&n)==1) {if (n%3) puts("Kiki"); else puts("Cici");}return 0;
}
View Code

 

 

 SG函数与SG定理

但是对于一些非常见博弈模型或者是模型变形规律不明显的,我们有一个大杀器:SG函数。通过SG函数我们能够快速直到某个点是必胜/必败态从而找到规律。

做了HDU-1848当作求SG函数的模板:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e3+10;
 4 int f[30],S[N],SG[N]; 
 5 
 6 void getSG(int n) {
 7     memset(SG,0,sizeof(SG));
 8     for (int i=1;i<=n;i++) {
 9         memset(S,0,sizeof(S));  //后继SG状态函数集合 
10         for (int j=0;j<=20&&f[j]<=i;j++) S[SG[i-f[j]]]=1;  //标记后继状态SG函数 
11         for (int j=0;;j++) 
12             if (!S[j]) {  //mex:后继SG第一个没出现的 
13                 SG[i]=j; break;
14             }
15     }
16 }
17 
18 int main()
19 {
20     int n,m,k;
21     f[0]=f[1]=1;
22     for (int i=2;i<=20;i++) f[i]=f[i-1]+f[i-2];  //求出可操作集 
23     getSG(1000);  //计算前1000的SG函数 
24     while (scanf("%d%d%d",&n,&m,&k) && (n||m||k)) {
25         if (SG[n]^SG[m]^SG[k]) printf("Fibo\n");  //多堆游戏XOR和 
26         else printf("Nacci\n");
27     }
28     return 0;
29 }
View Code

 HDU-1536

SG函数直接应用。要注意这题输入的操作集合不是升序的要先排序才行。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int k,n,m,f[110],S[N],SG[N]; void getSG(int n) {memset(SG,0,sizeof(SG));memset(S,-1,sizeof(S));for (int i=1;i<=n;i++) {for (int j=1;j<=k&&f[j]<=i;j++) S[SG[i-f[j]]]=i;  for (int j=0;;j++) if (S[j]!=i) {  SG[i]=j; break;}}
}int main()
{while (scanf("%d",&k) && k) {for (int i=1;i<=k;i++) scanf("%d",&f[i]);sort(f+1,f+k+1);getSG(10000);scanf("%d",&n);for (int i=1;i<=n;i++) {int m,tmp=0; scanf("%d",&m);for (int j=1;j<=m;j++) {int x; scanf("%d",&x);tmp^=SG[x];}if (tmp==0) printf("L"); else printf("W"); }puts("");}return 0;
}
View Code

HDU-3980

这道题会难一些。首先原来是一个环不好处理,但是我们注意到只要第一步下手后就会变成链,所以我们一开始从n-m这条链开始求SG函数。那么假设此时是一条长度为n的链,我们在当前选手在上面选择了长度为m的区间染色,之后这条链就会分割成两段分别是i和n-i-m的后继状态,于是此时就会变成两个游戏,然后根据多堆Nim博弈异或和的结论,后继状态的SG函数就是SG[i]^SG[n-i-m],所以我们就能标记所有后继的SG函数得到当前状态的SG函数。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,m,SG[N],S[N];int getSG(int n) {if (n<m) return 0;if (SG[n]!=-1) return SG[n];for (int i=0;n-i-m>=0;i++) S[getSG(i)^getSG(n-i-m)]=n;  //Nim博弈 for (int i=0;;i++)if (S[i]!=n) {SG[n]=i; break;} return SG[n];    
}int main()
{int T,Case=0; cin>>T;while (T--) {scanf("%d%d",&n,&m);memset(SG,-1,sizeof(SG));memset(S,-1,sizeof(-1));SG[0]=0;if (n<m || getSG(n-m)) printf("Case #%d: abcdxyzk\n",++Case);else printf("Case #%d: aekdycoin\n",++Case);}return 0;
}
View Code

 POJ-2505

SG函数应该很容易求。但是此题的数字非常大数组决定存不下,可以考虑用map计算SG函数可以获得AC。

#include<cstdio>
#include<iostream>
#include<map>
using namespace std;
typedef long long LL;
LL n;
map<LL,LL> SG;LL getSG(LL x) {if (x>=n) return 0;if (SG.count(x)) return SG[x];map<LL,int> S;for (int i=2;i<=9;i++) S[getSG(x*i)]=1;for (int i=0;;i++)if (!S.count(i)) return SG[x]=i;
}int main()
{while (scanf("%lld",&n)==1) {SG.clear();if (getSG(1)) printf("Stan wins.\n"); else printf("Ollie wins.\n");}return 0;
}
View Code

 

其他题目练习:

POJ-2484

很经典的一道题。给n个连成环的硬币,每次每人可以取一个或者相邻的两个硬币,最后取不到硬币的人输掉。这题要运用一种平均分然后不断模仿对方决策得到必胜的思想。首先如果硬币个数<=2先手必胜,大于3的时候第一个人取完之后环会变成一条链,然后无论第一个人取的是一个还是两个第二个人都可以根据第一个人取的数量和位置做出“把剩下硬币取成完全相同的两条链”(这里要重点理解)。然后通过模仿对方达到不败之地。所以硬币数量>=3时候先手必败。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e6+10;
int n,m;int main()
{while (scanf("%d",&n)==1 && n) {if (n<=2) puts("Alice");else puts("Bob");}return 0;
}
View Code

POJ-2425

图上的博弈:一个n个点的有向无环图,有某些点有硬币,每次没人只可以把一个棋子往前推一步(当然是沿着边的方向推),最后不能推的人输掉。尽管是在DAG上的博弈,但是SG函数的求法还是那样,标记所有后继状态之后mex。然后有几个棋子就是XOR和即可。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int N=1e3+10;
int n,m,q,SG[N];
vector<int> G[N];int getSG(int x) {if (SG[x]!=-1) return SG[x];int S[N]={0};for (int i=0;i<G[x].size();i++) {int y=G[x][i];S[getSG(y)]=1;}for (int i=0;;i++)if (S[i]!=1) return SG[x]=i;
}int main()
{while (scanf("%d",&n)==1) {for (int i=1;i<=n;i++) {G[i].clear();int t; scanf("%d",&t);for (int j=1;j<=t;j++) {int x; scanf("%d",&x); x++;G[i].push_back(x);}}memset(SG,-1,sizeof(SG));while (scanf("%d",&q) && q) {int ans=0;for (int j=1;j<=q;j++) {int x; scanf("%d",&x); x++;ans^=getSG(x);}printf("%s\n",ans?"WIN":"LOSE");}}return 0;
}
View Code

POJ 1704 Georgia and Bob

一列格子上有n个棋子,每次没人可以选择一个棋子往左移动若干步,棋子不能越过1格子,棋子也不能越过其他棋子移动,不能移动的人输掉。这题真的挺巧妙的,听大佬说这是一种叫阶梯博弈的博弈模型。我们先考虑对于一组相邻的棋子,这种情况肯定是先手必败,因为先手移动x格同时后手可以用后面那个棋子移动相同格。那么我们把棋子两两配对,那么两两配对的时候前面棋子的移动其实是没有意义的,因为与其配对的后面棋子可以做一模一样的操作。所以唯一的变数变成了两两配对的一组棋子间的间隙。

所以解法就是把棋子两两匹配,奇数时候第一个棋子和格子1匹配,然后对于每一组格子间的间隙当成一堆Nim游戏,求出所有Nim游戏的和就是答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e3+10;
int n,a[N];int main()
{int T; cin>>T;while (T--) {scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);sort(a+1,a+n+1);int ans=0;for (int i=n;i>0;i-=2) ans^=a[i]-a[i-1]-1;printf("%s\n",ans?"Georgia will win":"Bob will win");}return 0;
}
View Code

 


POJ 1740 A New Stone Game
POJ 2068 Nim
POJ 3480 John
POJ 2348 Euclid's Game
HOJ 2645 WNim
POJ 3710 Christmas Game 
POJ 3533 Light Switching Game

HOJ 4388 Stone Game II

ZJU 3057 beans game

转载于:https://www.cnblogs.com/clno1/p/11231919.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Element-UI中Drawer抽屉去除标题自带蓝色框

当点击事件drawertrue时&#xff0c;抽匣回打开 这时抽匣的标题会出现一个难看的蓝色边框&#xff0c;一会就会消失&#xff0c;但是好丑&#xff0c;所以要去掉它 解决方法 /deep/ :focus {outline: 0;} vue组件中&#xff0c;在style设置为scoped的时候&#xff0c;里面在…

Java生鲜电商平台-高并发核心技术订单与库存实战

Java生鲜电商平台-高并发核心技术订单与库存实战 一、 问题 一件商品只有100个库存&#xff0c;现在有1000或者更多的用户来购买&#xff0c;每个用户计划同时购买1个到几个不等商品。 如何保证库存在高并发的场景下是安全的&#xff1f; &#xff08;1&#xff09;不多发 &…

Vue2 MVVM 双向绑定(数据劫持+发布者-订阅者模式)

参考文献&#xff1a;https://www.cnblogs.com/libin-1/p/6893712.html https://juejin.im/post/5b2f0769e51d45589f46949e MVVM拆开来即为Model-View-ViewModel&#xff0c;有View&#xff0c;ViewModel&#xff0c;Model三部分组成。View层代表的是视图、模版&#xff0c;负…

常用的激活函数

1.阶跃函数 &#xff0c;值域{0,1} 1 def step_function(x): 2 return np.array(x>0,dtypenp.int) 2.sigmoid函数 &#xff0c;值域(0,1) 1 def sigmoid(x): 2 return 1/(1np.exp(-x)) 3.relu函数 &#xff0c;值域[0&#xff0c;∞&#xff09; 1 def relu(x): 2 …

前端优化-vue-cli4安装webpack-bundle-analyzer分析包文件

使用vue-cli3创建了一个工程目录&#xff0c;技术栈为vue-cli3vue-routervuexelement-uiv-chartsaxios。但是等到项目开发完后&#xff0c;发现生成的app.js特别大&#xff0c;接近10M。为了优化项目性能&#xff0c;需要使用webpack-bundle-analyzer分析包文件&#xff0c;找出…

不要再问我三次握手和四次挥手

三次握手和四次挥手是各个公司常见的考点&#xff0c;也具有一定的水平区分度&#xff0c;也被一些面试官作为热身题。很多小伙伴说这个问题刚开始回答的挺好&#xff0c;但是后面越回答越冒冷汗&#xff0c;最后就歇菜了。 见过比较典型的面试场景是这样的: 面试官&#xff1…

VScode PowerShell运行脚本报错禁止运行脚本解决方式图文

今天在新Windows电脑上用VScode的终端PowerShell运行一个脚本的时候&#xff0c; 错误 在vscode终端运行vue -V查看版本失败 PS C:\Users\11388> vue -V vue : 无法加载文件 E:\NodeJs\node_global\vue.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xf…

添加右键用Sublime Text3 打开文件和文件夹

最近重新装了一下系统&#xff0c;右键没有用Sublime Text 3打开的选项了&#xff0c;于是查了一下解决方案 1、环境 Win10和Win7都可以Sublime Text 3最新版本以下为Win10系统下截图 2、添加右键打开文件 Win R&#xff0c;输入regedit,打开注册表 找到HKEY_CLASSESS_ROOT…

Windows Mobile Widget Emulator

今天Vimpyboy 在codeplex发布了Windows Mobile Widget Emulator。这是一个用来调试Windows Mobile 6.5 Widget的工具&#xff0c;我在做Windows Mobile 6.5 新功能widget开发 的时候就发现调试Widget很麻烦。也有想法做一个Emulator&#xff0c;其实这个Emulator目标很明显&…

AttributeError: Can only use .str accessor with string values, which use np.object_ dtype in pandas

忘记网址了…… 问题&#xff1a; 分析思路与解决方法&#xff1a; 转载于:https://www.cnblogs.com/bravesunforever/p/11247988.html

Java生鲜电商平台-促销架构以及秒杀解决方案实战

Java生鲜电商平台-促销架构以及秒杀解决方案实战 背景:随着这几年的电商的大热,我们经常看到一些商家为了促销和快速收益,纷纷推出了秒杀活动.不管是日常的超市里面的促销,明星演唱会门票售卖,还是春节订阅火车票,等等我们都能看到秒杀活动的影子. 1. 构建秒杀活动架构 1.1 说明…

PHP Cookie处理

Cookie 是什么&#xff1f; cookie是保存在客户端的信息包&#xff08;一个文件&#xff09; cookie 常用于识别用户。 cookie 是一种服务器留在用户计算机上的小文件。每当同一台计算机通过浏览器请求页面时&#xff0c;这台计算机将会发送 cookie。通过 PHP&#xff0c;您能…

PHP-连接数据库

1.2 连接数据库 通过PHP做MySQL的客户端 1.2.1 开启mysqli扩展 在php.ini中开启mysqli扩展 extensionphp_mysqli.dll开启扩展后重启服务器&#xff0c;就可以使用mysqli_函数了&#xff0c;1.2.2 连接数据库 创建news数据库 -- 创建表 drop table if exists news; create …

python模块初始与time、datetime及random

模块初始与time、datetime及random 模块初始 模块的概念&#xff08;本质为一个py文件&#xff09; python模块可以将代码量较大的程序分割成多个有组织的、彼此独立但又能互相交互的代码片段&#xff0c;这些自我包含的有组织 的代码段就是模块&#xff0c;模块在物理形式上表…

PHP-面向对象编程教程

1.2 面向对象介绍 1.2.1 介绍 面向对象是一个编程思想。编程思想有面向过程和面向对象 面向过程&#xff1a;编程思路集中的是过程上 面向对象&#xff1a;编程思路集中在参与的对象 以去饭馆吃饭为例&#xff1a; ​ 面向过程&#xff1a;点菜——做菜——上菜——吃饭—…

Java生鲜电商平台-统一异常处理及架构实战

Java生鲜电商平台-统一异常处理及架构实战 补充说明&#xff1a;本文讲得比较细&#xff0c;所以篇幅较长。 请认真读完&#xff0c;希望读完后能对统一异常处理有一个清晰的认识。 背景 软件开发过程中&#xff0c;不可避免的是需要处理各种异常&#xff0c;就我自己来说&…

VScode新建自定义模板快捷方式

VS新建vue文件的自定义模板 在使用vscode开发的时候&#xff0c;新建vue文件是不可或缺的&#xff0c;但是VSCode并没有vue文件的初始化模板&#xff0c;这个需要自定义模板。 我们可以使用vscode的snippets在新建.vue 文件后轻松获得一套模板。 具体步骤 打开VSCode -> …

cookbook_数据结构和算法

1.1将数据分解为单独的变量list_a [1,2,3,4,5,6,7,8,9] a,b,c,d,e,f,g,h,i list_a print(a,b,c,d,e,f,g,h,i) #使用相等数量的参数来接收_,b,c,d,e,f,g,h,_ list_a print(b,c,d,e,f,g,h) #不要的数据使用一个没有用的变量接收 View Code1.2从任意长度的可迭代对象中分解元素…

机器学习概览

什么是机器学习&#xff1f; 广义概念&#xff1a; 机器学习是让计算机具有学习的能力&#xff0c;无需明确的编程 —— 亚瑟萨缪尔&#xff0c;1959 工程概念&#xff1a; 计算机程序利用经验 E 学习任务 T&#xff0c;性能是 P&#xff0c;如果针对任务 T 的性能 P 随着经验 …

SQL on and 和 on where 的区别

on and 和 on where 的 区别 在使用 left join 时, on and 和 on where 会有区别&#xff1b;1. on的条件是在连接生成临时表时使用的条件,以左表为基准 ,不管on中的条件真否,都会返回左表中的记录  on 后面 and 都是对右表进行筛选 2.where是全部连接完后&#xff0c;对临时…