HDU1848 Fibonacci again and again【博弈】

题目链接:

?pid=1848

题目大意:

二个人玩取石子游戏,一共有三堆石子,分别为m、n、p个。两个人轮流取石子,每次可以任选一堆石子,

然后取斐波那契数列中的f(n)个。每次都使用最优策略,先取完的人获胜。问:先手的人会赢还厚后手的人会

赢?

思路:

这是一道博弈题。

Fibo[] = {1,2,3,5,8,13,21,…}。根据题意每次只能取fibo[i]个。则:

1.如果只有1堆m个,而m是某个fibo[i],则m是必胜点。m = 1,2,3,5,8,13,21,…是必胜点。

可以看出来0,4就是必败点。如果从m中取走k个(k是某个fibo[i]),m-k是必败点的话,则m

是必胜点。比如说从6个中取走2个,6-2 = 4,4是必败点,则6是必胜点;从7个中取走3个,

7-3 = 4,4是必败点,,则7是必胜点,同理9也是 必胜点。

当m = 10的时候,从m中无论取多少个都是必胜点。10-1=9,10-2=8,10-3=7,10-5=5,

10-8=2,则10是必败点。

这样子递推能求出只有1堆的时候,所有必胜点和必败点。

现在考虑一堆m个,一堆n个的情况。

如果m是必败点,n是必败点,则两堆组合(m,n)也是必败点。

这样可以知道(4,10)必败、(4,4)必败、(4,5)必胜。

这是因为:

必败 && 必败 == 必败

必胜 && 必胜 == 必胜

两堆状态一致。

推广为三堆状态:

必败 && 必败 && 必败 == 必败

必胜 && 必胜 && 必胜 == 必胜

设必败点为0,必胜点为1,三堆的状态分别为:sg[N],sg[M],sg[P],如果开始

三堆都为必败点,则先手必败,相反的话,则必胜。判断三堆都为必败点,只要三

堆状态都为0即可,即sg[N]^sg[M]^sg[P] == 0。

参考博客:

AC代码:

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;int f[1100],sg[1100],b[1100];int main(){f[1] = 1,f[2] = 2;for(int i = 3; ; ++i){f[i] = f[i-1] + f[i-2];if(f[i] >= 1000)break;}sg[0] = 0,sg[1] = 1;for(int i = 1; i <= 1000; ++i){memset(b,0,sizeof(b));for(int j = 1; f[j] <= i; ++j)b[sg[i-f[j]]] = 1;for(int j = 0; j <= 1000; ++j){if(!b[j]){sg[i] = j;break;}}}int N,M,P;while(cin >> N >> M >> P && (N||M||P)){if(sg[N]^sg[M]^sg[P])cout << "Fibo" << endl;elsecout << "Nacci" << endl;}return 0;}

与那些新人和旧人们共同经历吧!

HDU1848 Fibonacci again and again【博弈】

相关文章:

你感兴趣的文章:

标签云: