SG函数入门

SG函数入门

必胜点与必败点

概念

P点:必败点,换句话说,就是在双方都选择最优策略的情况下,谁处于此状态谁必败。

N点:必胜点,换句话说,就是在双方都选择最优策略的情况下,谁处于此状态谁必胜。

性质

1.所有的终结点都是必败点P。

2.从任意的必胜点N进行操作,至少有一种方式到达一个必败点。

3.从任意的一个必败点P进行操作,只可能到达必胜点N。



我们研究必胜点与必败点的目的是以此为题来简化博弈的情况,有助于我们分析策略。通常我们分析必胜点和必败点都是以终结点为起始点进行逆序分析。

我们以一道题为例hdu 1847 Good Luck in CET-4 Everybody!

例题hdu 1847 Good Luck in CET-4 Everybody!

题目描述

大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知道的Kiki和Cici都是如此。当然,作为在考场浸润了十几载的当代大学生,Kiki和Cici更懂得考前的放松,所谓“张弛有道”就是这个意思。这不,Kiki和Cici在每天晚上休息之前都要玩一会儿扑克牌以放松神经。
“升级”?“双扣”?“红五”?还是“斗地主”?
当然都不是!那多俗啊~
作为计算机学院的学生,Kiki和Cici打牌的时候可没忘记专业,她们打牌的规则是这样的:
1、 总共n张牌;
2、 双方轮流抓牌;
3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
假设Kiki和Cici都是足够聪明(其实不用假设,哪有不聪明的学生~),并且每次都是Kiki先抓牌,请问谁能赢呢?
当然,打牌无论谁赢都问题不大,重要的是马上到来的CET-4能有好的状态。

题目大意

现在有n张牌两个人取每次每个人只能取\(2^k\)张牌问是否先手必胜(肯定有万恶的多组数据)

当 n = 0 时,显然为必败点,因为此时你已经无法进行操作了

当 n = 1 时,因为你一次就可以拿完所有牌,故此时为必胜点

当 n = 2 时,也是一次就可以拿完,故此时为必胜点

当 n = 3 时,要么就是剩一张要么剩两张,无论怎么取对方都将面对必胜点,故这一点为必败点。

以此类推,最后你就可以得到;

? n : 0 1 2 3 4 5 6 ...

position: P N N P N N P ...

然后我们发现这道题的 P/N点的分布是有规律的,所以我们就可以O(T)的求解这道题了。



然后呢我们来考虑更加复杂的一个问题hdu 2147 kiki‘s game

例题hdu 2147 kiki‘s game

题意

先说题意,有两个人在玩一个方格游戏,起初是一个n×m的方格,刚开始在(1,m)坐标处有一个石子,每一次每个人可以把石子移向向,向,向左下,等到当前的人无法进行移动时,这个人失败,每次都是先手先走,问最终的答案。

思路

这是一道非常裸的NP状态转移的博弈问题。

这类题我们最好画一个表格,然后发挥自己的想象去找规律。

由于我们每次只能向左下角走,所以显然左下角为必败点。

那么所有可以到达这个点的点都为必胜点,然后我们一步步往下推最后一定可以得到一个类似这样的表格。

P N P N
N N N N
P N P N
N N N N
P N P N

我们可以发现规律只有当行列都为奇数时才为必败点,其他情况均为必胜点

所以这道题当行列都为奇数时Kiki无法赢得比赛。

SG 函数

首先我们需要先了解一个运算mex,这是一个对于集合的运算,mex(S)表示集合S中最小没有出现过的自然数。例如:mex{0,1,2,4}=3,mex{2,3,5}=0,mex{}=0

对于任意状态x,我们定义SG(X)=mex(S),其中S表示x的后继状态的SG函数值的集合。举个栗子:x有三个后继状态分别为SG(a),SG(b),SG(c);那么SG(x)=mex{SG(a),SG(b),SG(c)}。这样的集合S的最终状态必然是空集,所以当某一点的SG(x)=0,当且仅当x为为必败点时成立。

Sprague-Grundy定理(SG定理)

游戏和的等于各个游戏的SG函数的Nim和。这样就可以把一个游戏分而治之,从而简化问题。而Bouton定理就是SG定理在Nin游戏中的直接应用,因为单堆的Nim游戏SG函数满足SG(x)=x.

举个栗子

取石子

题面

有1堆n个的石子,每次只能取{ 1, 3, 4 }个石子,先取完石子者胜利,那么各个数的SG值为多少?

思路

先找终结点当个数为0时。那么有SG[0]=0,f[]={1,3,4}.

x=1时,可以取走1-f[1]个石子,剩余{0}个,所以SG[1]=mex{SG[0]}=mex{0}=1;

x=2时,可以取走2-f[1]个石子,剩余{1}个,所以SG[2]=mex{SG[1]}=mex{1}=0;

x=3时,可以取走3 - f{1,3}个石子,剩余{2,0}个,所以 SG[3] = mex{SG[2],SG[0]} = mex{0,0} =1;

x=4 时,可以取走4- f{1,3,4}个石子,剩余{3,1,0}个,所以SG[4]=mex{SG[3],SG[1],SG[0]} = mex{1,1,0} = 2;

x=5 时,可以取走5 - f{1,3,4}个石子,剩余{4,2,1}个,所以SG[5]=mex{SG[4],SG[2],SG[1]} =mex{2,0,1} = 3;

以此类推……

x 0 1 2 3 4 5 6 7
SG[X] 0 1 0 1 2 3 2 0

由上述实例我们就可以得到SG函数值求解步骤,那么计算1~n的SG函数值步骤如下:

1、使用 数组f 将 可改变当前状态 的方式记录下来。

2、然后我们使用 另一个数组 将当前状态x 的后继状态标记。

3、最后模拟mex运算,也就是我们在标记值中 搜索 未被标记值 的最小值,将其赋值给SG(x)。

4、我们不断的重复 2 - 3 的步骤,就完成了 计算1~n 的函数值。

//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;
        }
    }
}

Fibonacci again and again

题面

任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的:
F(1)=1;
F(2)=2;
F(n)=F(n-1)+F(n-2)(n>=3);
所以,1,2,3,5,8,13……就是菲波那契数列。
在HDOJ上有不少相关的题目,比如1005 Fibonacci again就是曾经的浙江省赛题。
今天,又一个关于Fibonacci的题目出现了,它是一个小游戏,定义如下:
1、 这是一个二人游戏;
2、 一共有3堆石子,数量分别是m, n, p个;
3、 两人轮流走;
4、 每走一步可以选择任意一堆石子,然后取走f个;
5、 f只能是菲波那契数列中的元素(即每次只能取1,2,3,5,8…等数量);
6、 最先取光所有石子的人为胜者;

假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。

数据范围为1000

#include <stdio.h>
#include <string.h>
#define MAXN 1000 + 10
#define N 20
int f[N],SG[MAXN],S[MAXN];
void getSG(int n){
    int i,j;
    memset(SG,0,sizeof(SG));
    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;
        for(j = 0;;j++) if(!S[j]){
            SG[i] = j;
            break;
        }
    }
}
int main(){
    int n,m,k;
    f[0] = f[1] = 1;
    for(int i = 2; i <= 16; i++)
        f[i] = f[i-1] + f[i-2];
    getSG(1000);
    while(scanf("%d%d%d",&m,&n,&k),m||n||k){
        if(SG[n]^SG[m]^SG[k]) printf("Fibo\n");
        else printf("Nacci\n");
    }
    return 0;
}

其他题目

POJ 2234 Matches Game
HOJ 4388 Stone Game II

POJ 2975 Nim
HOJ 1367 A Stone Game
POJ 2505 A multiplication game
ZJU 3057 beans game
POJ 1067 取石子游戏
POJ 2484 A Funny Game
POJ 2425 A Chess Game
POJ 2960 S-Nim
POJ 1704 Georgia and Bob
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

原文地址:https://www.cnblogs.com/My-snowing/p/10466769.html

时间: 2024-09-27 22:45:11

SG函数入门的相关文章

sg函数入门理解

首先理解sg函数必须先理解mex函数 mex是求除它集合内的最小大于等于0的整数,例:mex{1,2}=0:mex{2}=0:mex{0,1,2}=3:mex{0,5}=1. 而sg函数是啥呢? 对于任意状态 x , 定义 sg(x) = mex(f),其中f 是 x 后继状态的sg函数值的集合(就是上述mex中的数值).最后返回值(也就是sg(x))为0为必败点,不为零必胜点. 看不懂,咱直接来个例子: 例如:取石子问题,有1堆n个的石子,每次只能取{1,3,4}个石子,先取完石子者胜利,那么

(博弈 sg函数入门) Brave Game -- hdu -- 1846

链接: http://acm.hdu.edu.cn/showproblem.php?pid=1846 首先来玩个游戏,引用杭电课件上的: (1) 玩家:2人:(2) 道具:23张扑克牌:(3) 规则:游戏双方轮流取牌:每人每次仅限于取1张.2张或3张牌:扑克牌取光,则游戏结束:最后取牌的一方为胜者. 想一下.. 首先申明一点,博弈的讨论是在大家都玩的最好的情况下讨论的.(如果2个玩家智商有差别,那就没法讨论了----开个玩笑哈.) 介绍概念:P点 即必败点,某玩家位于此点,只要对方无失误,则必败

Light OJ 1296 - Again Stone Game (博弈sg函数递推)

F - Again Stone Game Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Description Alice and Bob are playing a stone game. Initially there are n piles of stones and each pile contains some stone. Alice stars the

TYVJ 2049 魔法珠 sg函数

题意:链接 方法:sg函数 解析: tyvj的题大部分都没题解啊- - 不过这样貌似会更好?感觉做这的题都需要自己动脑啊- - 虽然嘴上说着好烦然而心里觉得好评? 回归正题 设sg[x]表示数x的sg值,这好像是废话 然后对于读入的a[i],将所有的a[i]的sg值异或起来如果不是零则先手赢反之后手 维护的时候有个坑. 每次求约数的时候,数组要在sg里开,因为如果递归下去的话,全局变量的话会被更改,会被坑死. 然后就是怎么维护了 对于x,先求约数 之后枚举哪个数不取,将其他的异或(或者先都异或起

hdu1848 Fibonacci again and again(SG函数博弈)

现在换是看不明白SG函数的求法什么的 暂时先当模板题吧 函数mex1就是求g(x) 然后异或 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; int k,fibo[100],f[10001]; int mex1(int p){ int i,t; bool g[101]={0}; for(i=0;i<k;i++){

HDU 2897-邂逅明下(sg函数)

邂逅明下 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 2897 Appoint description:  System Crawler  (2015-03-13) Description 当日遇到月,于是有了明.当我遇到了你,便成了侣. 那天,日月相会,我见到了你.而且,大地失去了光辉,你我是否成侣?这注定是个凄美的故事.(以上是废

hdu 1536 S-Nim 博弈论,,求出SG&#39;函数就可以解决

S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4975    Accepted Submission(s): 2141 Problem Description Arthur and his sister Caroll have been playing a game called Nim for some time now

SG函数

转自:Angel_Kitty Sprague-Grundy定理(SG定理): 游戏和的SG函数等于各个游戏SG函数的Nim和.这样就可以将每一个子游戏分而治之,从而简化了问题.而Bouton定理就是Sprague-Grundy定理在Nim游戏中的直接应用,因为单堆的Nim游戏 SG函数满足 SG(x) = x.对博弈不是很清楚的请参照http://www.cnblogs.com/ECJTUACM-873284962/p/6398385.html进行进一步理解. SG函数: 首先定义mex(min

算法笔记--sg函数详解及其模板

sg函数大神详解:http://blog.csdn.net/luomingjun12315/article/details/45555495 模板: int f[N],SG[N]; bool S[M]; void getSG(int n) { memset(SG,0,sizeof(SG)); for(int i=1;i<=n;i++) { memset(S,false,sizeof(S)); for(int j=1;f[j]<=i&&j<M;j++) { S[SG[i-f