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