sg

POJ 2311. Cutting Game

烈酒焚心 提交于 2020-03-21 03:11:03
Link 题意: 给定一张 \(N*M(2 \le n,m \le 200)\) 的矩形网格纸,两名玩家轮流行动。 在每一次行动中,可以任选一张矩形网格纸,沿着某一行或某一列的格线,把它剪成两部分。 首先剪出 \(1*1\) 的格纸的玩家获胜。 两名玩家都采取最优策略行动,求先手是否能获胜。 思路: 得到 \(1*1\) ,除了会经过 \(1*n\) 和 \(n*1\) 这两种必胜局面外,一定会经过 \(2*2\) , \(2*3\) , \(3*2\) 这三种局面,而这三种局面往后必得到前两种必胜局面,所以这三种局面为必败局面 我们以这三种局面为最终局面进行递推 \(sg[i,j]=mex((sg[x,j] \bigoplus s[i-x,j])(2<=x<=i/2)\cup sg[i,x]\bigoplus s[i,j-x])(2<=x<=j/2))\) 代码: #include<iostream> #include<cstring> using namespace std; const int N=210; int sg[N][N]; bool vis[N]; int main() { //freopen("in.txt","r",stdin); ios::sync_with_stdio(false); cin.tie(0); memset(sg,-1,sizeof sg);

博弈论学习笔记

限于喜欢 提交于 2020-03-10 18:59:27
博弈论学习笔记 一些概念 组合博弈(combinatorial games) 两个玩家,均可获得完全信息,每一操作均不受随机性影响(例如poker就不是组合博弈) 有偏博弈 两个玩家可以进行的操作有区别,例如象棋和跳棋 无偏博弈 两名选手交替对游戏进行移动,每次一步,选手可以在有限的合法移动集合中任选一种进行移动,双方均知道游戏的完整信息。 对于游戏的任何一种可能的局面,合法的移动集合只取决于这个局面本身,不取决于轮到哪名选手操作、以前的任何操作、骰子的点数或者其他因素。 如果轮到某名选手移动,且这个局面的合法的移动集合为空(也就是说此时无法进行移动),则这名选手负。 游戏中的同一个状态不可能多次抵达,游戏以玩家无法行动结束,且游戏一定会在有限步后以非平局结束,即状态图无环。 大部分的棋类游戏都不是公平组合游戏。 NIM游戏 有N堆石子,每堆石子的数量是 \(a_1,a_2,a_3,...,a_n\) ,合法的移动是”选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被 拿空了 ,则 判负 (因为他此刻没有任何合法的移动)。 我们将图上的每一个局面看成图上的一个节点,所有的合法节点形成一个DAG。 P-position:先手必败 N-position:先手必胜 例如3堆石子的NIM游戏 (0,0,0)是必败局面。 (0,0,n)是必胜局面 (0,1,1

AcWing 1319. 移棋子游戏

不想你离开。 提交于 2020-03-07 14:33:58
sg函数是一张有向无环图 尼姆博弈对每一张图sg(值)进行游戏 就是加强版的集合尼姆博弈(集合尼姆博弈中拓展是根据集合可能的新状态),这里是回归本质,sg操作是对每个状态拓展出边,并通过出边sg值集合进行mex操作,来求当前点的sg值 vector < int > G [ 2005 ] ; int fg [ 2005 ] ; int n , m , k , x , y ; int sg ( int x ) { if ( fg [ x ] != - 1 ) return fg [ x ] ; unordered_set < int > s ; for ( auto i : G [ x ] ) s . insert ( sg ( i ) ) ; for ( int i = 0 ; ; ++ i ) //mex if ( ! s . count ( i ) ) return fg [ x ] = i ; } int main ( ) { cin >> n >> m >> k ; f ( i , 1 , m ) { scanf ( "%d%d" , & x , & y ) ; G [ x ] . emplace_back ( y ) ; } int ans = 0 ; memset ( fg , - 1 , sizeof fg ) ; f ( i , 1 , k ) { scanf ( "

L - River Game(博弈 SG函数)

有些话、适合烂在心里 提交于 2020-03-01 19:07:30
https://vjudge.net/problem/Gym-102501L 题意: L题是个游戏, N ⋅ N N\cdot N N ⋅ N 网格中,有连通(上下左右)的星,每块连通的星会接触左边界和右边界,大小至多2N。两块连通的星的任意两个点之间距离至少为3。 现在轮流放置照相机,需要接触星,接触同一块连通的星的照相机不能接触,x不能放置,问先手赢还是后手赢。 解析: 距离为3说明两个大块之间的game独立。一个大块上放照相机不能互相接触,说明可以将可以放照相机的’.'块通过连通性再次分割。 最后对于一个连通的’.‘块,由于保证一个大块最多只有20个点,所以’.'块感觉也差不多20个。 所以可以用状压dp跑SG函数,代码中的deal2函数处理的是这个。二进制中,1代表可以放,0代表已经被放置或与放置的相邻。答案的SG值为所有SG值的异或。SG不为0时先手赢。 代码: /* * Author : Jk_Chen * Date : 2020-03-01-14.47.40 */ # include <bits/stdc++.h> using namespace std ; # define LL long long # define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++) # define per(i,a,b) for(int

模板 - 数学 - 博弈论 - SG函数

心已入冬 提交于 2020-02-12 03:20:12
f[i]表示状态i的后继状态,把它的后继状态push_back()进去,然后调用getSG()就可以得到SG函数。无法转移的状态都是失败状态,这种写法貌似只能向标号更小的状态转移(本身这个图就是DAG,就有拓扑序,所以本质上无所谓,更何况取石子非常直观),所以一般f[0]就是失败状态。当然也可能会有别的失败状态。 多个公平组合游戏的和,只需要把他们分别的SG函数求出来然后求个异或和即可。 vector<int> f[1005]; int SG[1005], S[1005]; int getSG() { for(int i = 0; i <= n; ++i) SG[i] = 0; for(int i = 1; i <= n; i++) { int l = f[i].size(); for(int j = 0; j <= l; j++) S[j] = 0; for(auto &j : f[i]) S[SG[j]] = 1; for(int j = 0; j <= l; j++) { if(!S[j]) { SG[i] = j; break; } } } return SG[n]; } 来源: https://www.cnblogs.com/KisekiPurin2019/p/12297664.html

SG函数

心不动则不痛 提交于 2020-02-11 08:37:41
只扔个板子吧 : void get_sg(int n) { memset(sg,0,sizeof(sg)); for(int i=1;i<=n;i++) { memset(S,0,sizeof(S)); for(int j=1;f[j]<=i&&j<=m;j++) { S[sg[i-f[j]]]=1; } for(int k=0;k<=n;k++) { if(!S[k]) { sg[i]=k; break; } } } } 来源: https://www.cnblogs.com/tlx-blog/p/12293737.html

【博弈论】

一曲冷凌霜 提交于 2020-02-05 22:48:58
巴什博奕 只有一堆n个物品,两个人轮流从这堆物品中取物, 规定每次至少取一个,最多取m个。最后取光者得胜。 分析 (1)当n≤m时,由于一次最少拿1个、最多拿m个,甲可以一次拿完,先手赢。 (2)当n=m+1时,无论甲拿走多少个(1~m个),剩下的都多于1个、少于等于m 个,乙都能一次拿走剩余的石子,后手取胜。 上面两种情况可以扩展为以下两种情况: A.如果n%(m+1)=0,即n是m+1的整数倍,那么不管甲拿多少,例如k个,乙都 拿m+1-k个,使得剩下的永远是m+1的整数倍,直到最后的m+1个,所以后拿 的乙一定赢。 B.如果n%(m+1)!=0,即n不是m+1的整数倍,还有余数r,那么甲拿走r个,剩下的是 m+1的倍数,这样就转移到了情况(A),相当于甲、乙互换,结果是甲赢。 例题: hdu 2147 题意: 在一个m*n的棋盘内,从(1,m)点出发,每次可以进行的移动是:左移一,下移一,左下移一。然后kiki每次先走,判断kiki时候会赢(对方无路可走的时候)。 分析: 我们可以把PN状态的点描绘出来: 可以发现 n,m 中有一个是2 的倍数,则 为先手获胜,反之,后手必胜。 code: 1 #include<bits/stdc++.h> 2 using namespace std; 3 int main( ) 4 { 5 int n,m; 6 while(scanf("

LGOJ1290 欧几里德的游戏

こ雲淡風輕ζ 提交于 2020-01-31 20:54:07
题目链接 P1290 and UVA10368 (双倍经验【虽然标签差距很有趣】) 题目大意 给定两个数 \(n\) 和 \(m\) ,每次操作可以用较大数减去较小数的正整数倍,不可以减成负数。 先获得一个 \(0\) 的人获胜,问先手是否必胜。 \(n,m \leq 2^{31}-1\) 多组数据。 Solution 一眼博弈论题吧2333 \(SG\) 函数和递归操作应该是摆在眼前的 先记较大数为 \(n\) ,较小数为 \(m\) 三种情况: 1.如果当前态的 \(n\) 和 \(m\) 中有一个已经是 \(0\) 了 显然 \(SG(now)=0\) ,这个人一定输了 2.如果 \(n\) 已经是 \(m\) 的倍数 一步操作就可以获胜, \(SG(now)=1\) 这个人一定赢了 (上两个都是终止态) 3. \(SG(n,m)=SG(n\space mod \space m,m)\) 这里需要理解一下: 我们假定我们要让这个式子成立 \[SG(n,m) \rightarrow SG(n-k \times m,m)\] 通过控制 \(k\) 的大小进行博弈,可以使得 \[SG(n \space mod \space m,m)= SG(n,m)\] 得证(其实对于“通过控制 \(k\) 的大小进行博弈”感性理解一下吧,具体过程不展开了) CODE #include <bits

吃鸡配置文件

心不动则不痛 提交于 2020-01-20 11:07:45
//自定义特效等级 [ScalabilityGroups] sg.ResolutionQuality=100.000000 //视野距离 sg.ViewDistanceQuality=1 sg.AntiAliasingQuality=0 sg.ShadowQuality=0 sg.PostProcessQuality=0 sg.TextureQuality=0 sg.EffectsQuality=0 sg.FoliageQuality=0 //语言 CultureName=zh-CN //回放 bUseClientReplay=True //死亡画面 bUseKillcam=True //垂直同步 bUseVSync=False // 全屏模式 0,全屏 1,全屏窗口化 2、窗口化 FullscreenMode=0 //全屏模式 LastConfirmedFullscreenMode=0 //最后设置全屏 PreferredFullscreenMode=0 //首选全屏 来源: https://www.cnblogs.com/bingxing/p/8598741.html

[UOJ266]Alice和Bob又在玩游戏

自作多情 提交于 2019-12-26 07:29:51
[UOJ266]Alice和Bob又在玩游戏 Tags:题解 作业部落 评论地址 TAG:博弈 题意 不同于树的删边游戏,删掉一个点删去的是到根的路径 题解 这题只和计算 \(SG\) 有关,博弈的有关内容可以移步 这篇博客 这和翻棋子游戏不同!每个点不能单独考虑 考虑计算一个游戏(子树 \(x\) )的 \(SG\) :对其后继状态取 \(mex\) 这里的后继状态是指去掉子树 \(x\) 内任意一个点所得的若干子游戏的异或和(联通块) 用 \(SG[x]\) 维护子树 \(x\) 游戏的 \(SG\) 值,考虑转移给父亲 \(y\) 游戏 \(y\) 可以删去 \(y\) 结点,后继状态便是 \(y\) 各儿子的 \(SG\) 的异或和 游戏 \(y\) 可以删去任意 \(x\) 子树内的点,这时 \(x\) 子树内删去任意结点的后继状态会多出 \(x\) 的兄弟 若 \(SG[x]=mex\{S\}\) ,这时我们要求一个数据结构能将 \(S\) 中每个元素异或上一个数再合并给 \(y\) 的 \(S_y\) 带懒标记的 \(Trie\) 就好了 代码 #include<iostream> #include<cstdio> #include<cstdlib> #define lc ch[x][0] #define rc ch[x][1] using namespace std