日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SG函数入门

發布時間:2023/12/10 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SG函数入门 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考博客:https://baike.baidu.com/item/SG%E5%87%BD%E6%95%B0/1004609

https://www.cnblogs.com/ECJTUACM-873284962/p/6921829.html

主要參考百度百科:

首先定義mex(minimal excludant)運算,這是施加于一個集合的運算,表示最小的不屬于這個集合的非負整數。例如mex{0,1,2,4}=3、mex{1,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函數的終態為 SG(x) = 0,當且僅當 x 為必敗點P時。

SG函數的性質:

首先,所有的terminal position(目標位置)所對應的頂點,也就是沒有出邊的頂點,其SG值為0,因為它的后繼集合是空集。然后對于一個g(x)=0的頂點x,它的所有前驅y都滿足 g(y)!=0。對于一個g(x)!=0的頂點,必定存在一個后繼y滿足g(y)=0

表明,頂點x所代表的postion(位置)是P-position(必敗點)當且僅當g(x)=0

?

SG值的意義

1,當g(x)=k時,表明對于任意一個0<=i<k,都存在x的一個后繼y滿足g(y)=i。為什么一定存在呢?

?因為mex函數運算時,g(y)等于最小的不屬于(y后繼狀態)這個集合的非負整數,換言之,y的后繼狀態一定有 [0,k-1] 這個范圍才會出現g(x)=k,k為不小于后繼狀態(集合),因為函數g就是按照mex運算得來的。

2,當某枚棋子的SG值是k時,我們可以把它變成0、變成1、……、變成k-1,但絕對不能保持k不變。這個聯想到Nim游戲, Nim游戲的規則就是:每次選擇一堆數量為k的石子,可以把它變成0、變成1、……、變成k-1,但絕對不能保持k不變。這表明,如果將n枚棋子所在的頂 點的SG值看作n堆相應數量的石子,那么這個Nim游戲的每個必勝策略都對應于原來這n枚棋子的必勝策略!

3,對于n個棋子,設它們對應的頂點的SG值分別為(a1,a2,…,an),再設局面(a1,a2,…,an)時的Nim游戲的一種必勝策略是把ai 變成k,那么原游戲的一種必勝策略就是把第i枚棋子移動到一個SG值為k的頂點。這就相當于可以看做,每次最聰明的操作是按照Nim游戲SG(N)值來移動,例如我們想把SG(N)變為SG(小于N),就滿足最聰明移動,但我們真正移動的又不是SG(N)的值,移動的是原來頂點N的值,咦,好像也是哦,沒關系,我們依舊移頂點N的值,只是說移動頂點N的值時,要滿足移動后頂點(小于N),SG(小于N)的值是我們想要的最聰明的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;}} }

?

給出一道入門級的題目

hdu 1848

#include <cstdio> #include<algorithm> #include<cstring> using namespace std; const int MAXN=1010; #define N 20 int f[N],SG[MAXN],S[MAXN];///f[]可走步數//S[]后繼存在狀態 void getSG(int n){int i,j;memset(SG,0,sizeof(SG));///PN點for(i = 1; i <= n; i++){///從i=1開始memset(S,0,sizeof(S));///每次初始化S[]后繼存在狀態for(j = 0; f[j] <= i && j < N; j++)///f[i]<i;S[SG[i-f[j]]] = 1;///f[]可走步數///S[]后繼存在狀態for(j = 0;;j++) if(!S[j]){///找出后繼存在狀態中的最小非負整數;SG[i] = j;?///最終得出該點i的SG值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);///得出所有點的SG函數值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; }

?

?

我的標簽:做個有情懷的程序員。

?

?

?

總結

以上是生活随笔為你收集整理的SG函数入门的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。