<font size=4>php
博弈论五大模型
前四大模型的深刻理解html
Bash博弈模型
有一堆数量为n的石头,双方轮流每次从堆中取至少1个石头最多m个石头,谁先取完谁赢。ios
设存在整数k和r使方程n=k*(m+1)+r成立,当r==0时先手必败,不然先手必赢。函数
结论:n%(m+1) == 0, 先手必败spa
Wythoff博弈模型
有两堆数量分别为x、y(x <= y)的石头,每次能够从一堆中取至少一个石头或者从两堆中取同等数量的石头,谁先取完谁赢。.net
结论:x == floor( (sqrt(5)+1)/2 )*(y-x), 知足等式时先手必败code
Nim博弈模型
有任意m堆、数量任意的石头,每次只能从一堆中获取至少1个石头,谁先取完谁赢htm
设石头堆Di,Di的异或和k = D1^D2^...^Di,当且仅当k == 0时先手必败,不然先手必赢blog
结论:D1^D2^...^Di == 0, 先手必败游戏
Fibonacci博弈模型
有一堆数量为n的石头,双方轮流从石头堆里取k[i]个石头(1≤k[i]≤2*k[i-1]),先取完的人获胜
当且仅当n不是斐波那契数时,先手必胜,不然先手必败
结论:Fib(n) == false, 先手必胜
SG函数
定义: P点:必败点,换而言之,就是谁处于此位置,则在双方操做正确的状况下必败。 ______ N点:必胜点,处于此状况下,双方操做均正确的状况下必胜。 定义:设mex{S}为集合S中第一个不存在的正整数 定义:设sg(x)为x状态的sg值,sg(x)=mex{S},其中S为x的后继状态的sg值的集合 当sg(x) == 0时, 没有获胜局面,此时处于P点 性质:一、全部终结点的sg值都为0,即sg(0) == 0 ______二、不管在N点如何操做,都至少存在一种状况进入P点 ______三、不管如何,P节点的后继节点必定是N节点 ______四、不管如何只能进入N点的点必定是P点
例题:HDU 1848:Fibonacci again and again
题解:假设只有一堆数量为n的石子
定义sg(x)函数为当前石子数量的sg函数,每次只能取Fib[]数列的数
sg[0] = 0, Fib[] = {1,2,3,5...}
当x == 1时,能够取Fib[1]个石子,剩余0个石子,sg[1] = mex{sg[0]} = mex{0} = 1;
当x == 2时,能够取Fib[2]、Fib[1]个石子,剩余一、0个石子sg[2] = mex{sg[1],sg[0]} = mex{0,1} = 2;
当x == 3时,能够取Fib[3]、Fib[2]、Fib[1]个石子,剩余二、一、0个石子,sg[3] = mex{sg[2],sg[1],sg[0]} = mex{2,1,0} = 3;
当x == 4时,能够取Fib[3]、Fib[2]、Fib[1]个石子,剩余三、二、1个石子,sg[4] = mex{sg[3],sg[2],sg[1]} = mex{3,2,1} = 0;
......
当x == n时,若sg[n] != 0,先手必胜
对于多堆石子,类比Nim游戏:
sg[n]^sg[m]^sg[k] == 0, 先手必败
#include<iostream> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> #include<string> #include<string.h> #include<queue> using namespace std; #define fi first #define se second #define mp make_pair #define pb push_back #define rep(i, a, b) for(int i=(a); i<(b); i++) #define sz(a) (int)a.size() #define de(a) cout<<#a<<" = "<<a<<endl #define dd(a) cout<<#a<<" = "<<a<<" " #define be begin #define en end typedef long long ll; typedef pair<int, int> pii; typedef vector<int> vi; const int N = 1005; vi f; void fib(){ f.pb(1), f.pb(1); for(int i = 1;f[i] < N;i++){ f.pb(f[i]+f[i-1]); } f.erase(f.begin()); } int sg[N]; void SG(){ vi::iterator it; sg[0] = 0; for(int i = 1;i < N;i++){ set<int> q; for(it = f.begin();it != f.end() && *it <= i;it++){ q.insert( sg[i-(*it)] ); } set<int>::iterator sit = q.begin(); int t = 0; for(;sit != q.end();sit++){ if(t < *sit) { break; } else t = *sit+1; } sg[i] = t; } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); fib(); SG(); int m,n,p; while(cin >> m >> n >> p){ if(m == 0) break; if((sg[m]^sg[n]^sg[p]) == 0) cout << "Nacci" << endl; else cout << "Fibo" << endl; } return 0; }