HDU 1848 博弈SG函式

2021-09-25 08:31:23 字數 1690 閱讀 9861

題目大意:

任何乙個大學生對菲波那契數列(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、  最先取光所有石子的人為勝者;

假設雙方都使用最優策略,請判斷先手的人會贏還是後手的人會贏。

題目思路:

由於乙個狀態的下乙個狀態只能是i-x(x是小於等於i的菲波那切數),所以很容易得到sg函式,然後對三堆石子的sg函式進行異或即可得到最後的答案。針對sg函式的相關前置技能請轉步相關部落格檢視。

以下是**:

迴圈寫法:

#include#include#include#include#includeusing namespace std;

#define inf 0x3f3f3f3f

#define rep(i,a,b) for(int i=a;i<=b;i++)

#define per(i,a,b) for(int i=a;i>=b;i--)

#define ll long long

const int maxn = 2e5+5;

int f[maxn],m,n,p,sg[maxn];

bool vis[maxn];

int main()

memset(sg,0,sizeof(sg));

rep(i,0,1000)

rep(j,0,1000)}}

while(~scanf("%d%d%d",&m,&n,&p)&&(m+n+p))

else

}return 0;

}

遞迴寫法:

#include#include#include#include#includeusing namespace std;

#define inf 0x3f3f3f3f

#define rep(i,a,b) for(int i=a;i<=b;i++)

#define per(i,a,b) for(int i=a;i>=b;i--)

#define ll long long

const int maxn = 1e3+5;

int f[maxn],m,n,p,sg[maxn];

int solve(int x)

rep(i,0,1000)if(!vis[i])return sg[x]=i;

}int main()

memset(sg,-1,sizeof(sg));

sg[0]=0;

while(~scanf("%d%d%d",&m,&n,&p)&&(m+n+p))

else

}return 0;

}

SG函式入門 HDU 1848

sg i 為0表示i節點先手必敗。首先定義mex minimal excludant 運算,這是施加於乙個集合的運算,表示最小的不屬於這個集合的非負整數 例如mex 3 mex 0 mex 0。對於乙個給定的有向無環圖,定義關於圖的每個頂點的sprague grundy 函式g如下 g x mex,...

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

摘自jumping frog聚聚的部落格 首先定義mex minimal excludant 運算,這是施加於乙個集合的運算,表示最小的不屬於這個集合的非負整數。例如 mex 3 mex 0 mex 0。對於乙個給定的有向無環圖,定義關於圖的每個頂點的sprague grundy函式g如下 g x ...

hdu 1848 sg博弈模版題

計算從1 n範圍內的sg值。array 儲存可以走的步數,array 0 表示可以有多少種走法 array需要從小到大排序 1.可選步數為1 m的連續整數,直接取模即可,sg x x m 1 2.可選步數為任意步,sg x x 3.可選步數為一系列不連續的數,用getsg 計算 int sg max...