什么是SG?+SG模板
先,定义一下 状态Position P 先手必败 N x先手必胜
操作方法: 反向转移
相同状态 不同位置 的一对 相当于无
对于ICG游戏,我们可以将游戏中每一个可能发生的局面表示为一个点。并且若存在局面i和局面j,且j是i的后继局面(即局面i可以转化为局面j),我们用一条有向边,从i出发到j,连接表示局面i和局面j的点。则整个游戏可以表示成为一个有向无环图:
根据ICG游戏的定义我们知道,任意一个无法继续进行下去的局面为终结局面,即P局面(先手必败)。在上图中我们可以标记所有出度为0的点为P点。接着根据ICG游戏的两条性质,我们可以逆推出所有点为P局面还是N局面:
对于一个游戏可能发生的局面x,我们如下定义它的sg值:
(1)若当前局面x为终结局面,则sg值为0。
(2)若当前局面x非终结局面,其sg值为:sg(x) = mex{sg(y) | y是x的后继局面}。
mex{a[i]}表示a中未出现的最小非负整数。举个例子来说:
mex{0, 1, 2} = 3, mex{1, 2}=0, mex{0,1,3}=2
我们将上图用sg函数表示后,得到:
可以发现,若一个局面x为P局面,则有sg(x)=0;否则sg(x)>0。同样sg值也满足N、P之间的转换关系:
若一个局面x,其sg(x)>0,则一定存在一个后续局面y,sg(y)=0。
若一个局面x,其sg(x)=0,则x的所有后续局面y,sg(y)>0。
由上面的推论,我们可以知道用N、P-Position可以描述的游戏用sg同样可以描述。并且在sg函数中还有一个非常好用的定理,叫做sg定理:
对于多个单一游戏,X=x[1..n],每一次我们只能改变其中一个单一游戏的局面。则其总局面的sg值等于这些单一游戏的sg值异或和。
先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Grundy函数g如下:g(x)=mex{ g(y) | y是x的后继 },这里的g(x)即sg[x]
例如:取石子问题,有1堆n个的石子,每次只能取{1,3,4}个石子,先取完石子者胜利,那么各个数的SG值为多少?
sg[0]=0,f[]={1,3,4},
x=1时,可以取走1-f{1}个石子,剩余{0}个,mex{sg[0]}={0},故sg[1]=1;
x=2时,可以取走2-f{1}个石子,剩余{1}个,mex{sg[1]}={1},故sg[2]=0;
x=3时,可以取走3-f{1,3}个石子,剩余{2,0}个,mex{sg[2],sg[0]}={0,0},故sg[3]=1;
x=4时,可以取走4-f{1,3,4}个石子,剩余{3,1,0}个,mex{sg[3],sg[1],sg[0]}={1,1,0},故sg[4]=2;
x=5时,可以取走5-f{1,3,4}个石子,剩余{4,2,1}个,mex{sg[4],sg[2],sg[1]}={2,0,1},故sg[5]=3;
以此类推.....
x 0 1 2 3 4 5 6 7 8....
sg[x] 0 1 0 1 2 3 2 0 1....
计算从1-n范围内的SG值。
f(存储可以走的步数,f[0]表示可以有多少种走法)
f[]需要从小到大排序
1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);
2.可选步数为任意步,SG(x) = x;
3.可选步数为一系列不连续的数,用GetSG()计算
//f[]:可以取走的石子个数
//sg[]:0~n的SG函数值
//hash[]:mex{}
int f[N],sg[N],hash[N];
void getSG(int n)
{
int i,j;
memset(sg,,sizeof(sg));
for(i=;i<=n;i++)
{
memset(hash,,sizeof(hash));
for(j=;f[j]<=i;j++)
hash[sg[i-f[j]]]=;
for(j=;j<=n;j++) //求mes{}中未出现的最小的非负整数
{
if(hash[j]==)
{
sg[i]=j;
break;
}
}
}
}
SG打表
//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
//n是集合s的大小 S[i]是定义的特殊取法规则的数组
int s[],sg[],n;
int SG_dfs(int x)
{
int i;
if(sg[x]!=-)
return sg[x];
bool vis[];
memset(vis,,sizeof(vis));
for(i=;i<n;i++)
{
if(x>=s[i])
{
SG_dfs(x-s[i]);
vis[sg[x-s[i]]]=;
}
}
int e;
for(i=;;i++)
if(!vis[i])
{
e=i;
break;
}
return sg[x]=e;
}
dfs
注意在SG表的初始化中,不用每次都初始;否则会T的,因为可以循环利用,这是一个强大的地方
HDU1536 实战
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int s[],sg[],n;
char op[];
int SG_dfs(int x)
{
int i;
if(sg[x]!=-)
return sg[x];
bool vis[];
memset(vis,,sizeof(vis));
for(i=;i<n;i++)
{
if(x>=s[i])
{
SG_dfs(x-s[i]);
vis[sg[x-s[i]]]=;
}
}
int e;
for(i=;;i++)
if(!vis[i])
{
e=i;
break;
}
return sg[x]=e;
}
int main()
{
int k;
while(scanf("%d",&n)!=EOF)
{
if(n==)
break;
for(int i= ; i<n ; i++)
scanf("%d",&s[i]);
sort(s,s+n);
int m,cnt=;
scanf("%d",&m);
memset(sg,-,sizeof(sg));
for(int i= ; i<m ; i++)
{ scanf("%d",&k);
int x=;
while(k--)
{
int w;
scanf("%d",&w);
x^=SG_dfs(w); }
if(x!=)
printf("W");
else
printf("L");
}
puts("");
} return ;
}
什么是SG?+SG模板的更多相关文章
- SG函数模板(转)
ps:sg[i]为0表示i节点先手必败. 首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数.例如mex{0,1,2,4}=3.me ...
- hdu 1536 SG函数模板题
S-Nim Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
- HDU 1847-Good Luck in CET-4 Everybody!-博弈SG函数模板
Problem Description 大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知道的Kiki和Cici都是如此.当然,作为在考场浸润了十几载 ...
- hdu1536&&hdu3023 SG函数模板及其运用
S-Nim Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u Submit Status ...
- SG函数模板
这篇虽然是转载的,但代码和原文还是有出入,我认为我的代码更好些. 转载自:http://www.cnblogs.com/frog112111/p/3199780.html 最新sg模板: //MAXN ...
- hdu 1536 S-Nim(sg函数模板)
转载自:http://blog.csdn.net/sr_19930829/article/details/23446173 解题思路: 这个题折腾了两三天,参考了两个模板,在这之间折腾过来折腾过去,终 ...
- 【非原创】sg函数模板
学习博客:戳这里 解题模型: 1.把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或. 即sg(G)=sg(G1)^sg(G2)^...^sg(Gn) ...
- SG函数 模板
int get_SG(int x) { ) return SG[x]; ]={}; ;i<=n;i++) ) v[get_SG(x-s[i])]=; int i; ;v[i];i++); SG[ ...
- Light OJ 1199:Partitioning Game(SG函数模板)
Alice and Bob are playing a strange game. The rules of the game are: 1. Initially there are n p ...
- SG函数模板(洛谷2197nim游戏
#include <iostream> #include <cstdio> #include <queue> #include <algorithm> ...
随机推荐
- POJ2774Long Long Message (后缀数组&后缀自动机)
问题: The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to ...
- NYOJ-求逆序数 ----------------待解决,WA
描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数 ...
- Poj1218_THE DRUNK JAILER(水题)
一.Description A certain prison contains a long hall of n cells, each right next to each other. Each ...
- 【转】Pro Android学习笔记(十六):用户界面和控制(4):ImageView控件
目录(?)[-] XML片段 代码设置ImageView ImageView是基础的控件,它是android.widget.ImageView的继承类. XML片段 <LinearLa ...
- wpf 可视化树的注意点
将控件的visibility 设置为collapse时,控件的可视化树并未生成,此时并不能查找到控件内的子控件. 若某控件想对用户不可见,且可以生成可视化树,则需将控件的visibility 设置为h ...
- nmp部署(Nginx Mariadb Php-fpm)
#主机:192.168.2.129(mini2) 既是php主机,也是数据库主机#yum install -y php php-fpm php-mysql mariadb-server[root@~ ...
- 【转】GitHub使用
1.设置Git全局用户配置 git config --global user.name "xxx" git config --global user.email xxx@gmail ...
- badblocks 检查磁盘损坏的区块
Linux badblocks命令用于检查磁盘装置中损坏的区块. 语法: badblocks [-svw][-b <区块大小>][-o <输出文件>][磁盘装置][磁盘区块数] ...
- [51nod1138]正整数分解为几个连续自然数之和
解题关键:注意为什么上界是$\sqrt {2n} $ 因为函数是关于m的递减函数,而结果必须为正整数 $a = \frac{{2n + m - {m^2}}}{{2m}} = \frac{n}{m} ...
- idea中java项目增加module后,增加的目录(src)无法增加包(Package)
在idea项目中,增肌model后,在项目根目录下增加src目录,右键发现无法增加包(Package). 仔细观察发现,新增加的src目录是棕色,而原先的src目录是浅蓝色的,见下图: 在src右键, ...