标签:
题目链接:
http://acm.hdu.edu.cn/showproblem.php?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。
参考博客:http://hi.baidu.com/king___haha/item/542a071140107f9598ce337c
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; else cout << "Nacci" << endl; } return 0; }
HDU1848 Fibonacci again and again【博弈】
标签:
原文地址:http://blog.csdn.net/lianai911/article/details/44936027