博弈(SG函式講解及其應用)(hdu1848)

2021-07-11 23:14:20 字數 1743 閱讀 5086

摘自jumping_frog聚聚的部落格:

首先定義mex(minimal excludant)運算,這是施加於乙個集合的運算,表示最小的不屬於這個集合的非負整數。例如

mex=3、mex=0、mex{}=0。

對於乙個給定的有向無環圖,定義關於圖的每個頂點的sprague-grundy函式g如下:g(x)=mex,這裡的g(x)即

sg[x]。

例如:取石子問題,有1堆n個的石子,每次只能取個石子,先取完石子者勝利,那麼各個數的sg值為多少?

sg[0]=0,f=,

x=1時,可以取走1-f個石子,剩餘個,mex=,故sg[1]=1;

x=2時,可以取走2-f個石子,剩餘個,mex=,故sg[2]=0;

x=3時,可以取走3-f個石子,剩餘個,mex=,故sg[3]=1;

x=4時,可以取走4-f個石子,剩餘個,mex=,故sg[4]=2;

x=5時,可以取走5-f個石子,剩餘個,mex=,故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()計算

模板1如下(sg打表):

//f:可以取走的石子個數

//sg:0~n的sg函式值

//hash:mex{}

int f[n];//可以取走的石子個數

int sg[n];//0~n的sg函式值

int hash[n];

void getsg(int n)中未出現的最小的非負整數

if(hash[j] == 0)}}

}

模板2如下(dfs):

//注意 s陣列要按從小到大排序 sg函式要初始化為-1 對於每個集合只需初始化1遍

//n是集合s的大小 s[i]是定義的特殊取法規則的陣列

int s[n],sg[n],n;

bool vis[n];

int dfs_sg(int x)

}for(int i = 0;; ++i)

}}

題目大意:

取石子問題,一共有3堆石子,每次只能取斐波那契數個石子,先取完石子者勝利,問先手勝還是後手勝?

演算法思想:

可選步數為一系列不連續的數(斐波那契數),可用getsg函式求得。 

最終結果是所有sg值異或的結果 。

#include #include #include using namespace std;

const int n = 1005;

int f[n];//可以取走的石子個數

int sg[n];//0~n的sg函式值

int hash[n];

void getsg(int n)中未出現的最小的非負整數

if(hash[j] == 0)}}

}int main()

return 0;

}

HDU 1848 博弈SG函式

題目大意 任何乙個大學生對菲波那契數列 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就是...

hdu 1536 博弈SG函式

1 include 2 include 3 include 4 include 5 include 6 include 7 include 8 include 9 10using namespace std 1112 const int max 109 13 int num max sg max 1...

博弈sg函式

sg函式 個人認為還是用於三種方法都無法解決的情況,如按特殊數字取石子 我們把整個博弈過程抽象為有向無環圖 1.幾項準備工作 mex求最小非負整數mex 0,mex 3,mex 0 sg x mex 就是石頭變少的繼 這樣sg就滿足幾個性質 1.sg x 0時,它的後繼都不為零 2.sg x 0時,...