博弈论入门
一.巴士博弈(Bash Game)
eg1.
拿石头,一共有n个石头Alice和Bob每人每回合可以拿1~m - 1个石头最后一个拿石头的人获胜。
n =
1 / 2 / 3 先手胜
4 后手胜
5 / 6 / 7 先手胜
8 后手胜
9 / 10 / 11 先手
n % m == 0 后手胜 n % m != 0 先手胜
#include <bits/stdc++.h>
using namespace std;
int c, n, m;
int main()
{
cin >> c;
while(c--)
{
cin >> n >> m ;
if(n % (m + 1) == 0) cout << "second\n";
else cout << "first\n";
}
return 0;
}
eg2.
Alice和Bob在下棋,一开始在(1,1)点每人每次可以向下,向右,向右下走一步,谁先走到(n,m)点谁就赢了。
必败态:
n = 1, m = 1; n = 3, m = 3;
如果n和m都是奇数,后手胜,否则先手胜
#include <bits/stdc++.h>
using namespace std;
int n, m;
int main()
{
while(cin >> n >> m && m + n)
{
if(n % 2 == 1 && m % 2 == 1) cout << "What a pity!\n";
else cout << "Wonderful!\n";
}
return 0;
}
二.Fibonacci’ s Game(斐波那契博弈)
eg1.
有一堆个数为n的石子,游戏双方轮流取石子,满足:
1)先手不能在第一次把所有的子取完;
2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。
必败态:n是斐波那契数列
必胜态:n不是
Zeckendort定理(齐肯多夫定理):任何正整数可以表示为若千个不连续的Fibonacci数之和。
#include <bits/stdc++.h>
using namespace std;
int n;
set<int> st;
int fib[50];
int main()
{
fib[1] = 1;
fib[2] = 1;
st.insert(1);
for(int i = 3; i <= 46; ++i)
{
fib[i] = fib[i - 1] + fib[i - 2];
st.insert(fib[i]);
}
while(cin >> n && n)
{
if(st.count(n)) cout << "Second win\n";
else cout << "First win\n";
}
return 0;
}
三.威佐夫博弈(Wythoff Game)
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多
者不限,最后取光者得获胜。
结论:首先黄金比例:r=1.618 = (sqrt(5.0) + 1) / 2,则给定两组石头堆(n,m),假设n>m,则当(n-m)*r==m时,先手输。否则后手输
*补充:floor函数
1、函数原型:
1 double floor (double x );
2 float floor (float x );
3 long double floor ( long double x );
2、功能:返回一个小于传入参数的最大整数
3、参数:x为将来被处理的数
4、返回值:返回不大于x的最大整数
(所以说这玩意跟(int)强制类型转换基本一样)
#include <bits/stdc++.h>
using namespace std;
int a, b, t;
double r, c;
int main()
{
r = (sqrt(5.0) + 1) / 2;
while(cin >> a >> b)
{
if(a < b) swap(a, b);
c = double(a - b);
t = (int)(r * c);
if(t == b) cout << 0 << '\n';
else cout << 1 << '\n';
}
return 0;
}
四.尼姆博弈(Nimm Game)
有n堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
必败态(奇异局势):所有堆石子数异或和为0
如何将一个非奇异局势(异或和不为0)转化为奇异局势?
以三堆石子为例(a,b,c)(a<b<c)只需将第三堆石子数变为a^b个即可,即从c中减去c - a^b个石子。
#include <bits/stdc++.h>
using namespace std;
int m;
int ar[105];
int ans, sum, k;
int main()
{
while(cin >> m && m)
{
ans = sum = 0;
memset(ar, 0, sizeof(ar));
for(int i = 1; i <= m; ++i)
{
cin >> ar[i];
ans ^= ar[i];
}
if(ans == 0) cout << 0 << '\n';
else
{
for(int i = 1; i <= m; ++i)
{
k = ans ^ ar[i];
if(ar[i] >= k) sum++;
}
cout << sum << '\n';
}
}
return 0;
}
还有一个叫sg函数的东东~~
(待更新)