斐波那契博弈
有一堆个数为n(n>=2)的石子,游戏双方轮流取石子,规则如下:
1)先手不能在第一次把所有的石子取完,至少取1颗;
2)之后每次可以取的石子数至少为1,至多为对手刚取的石子数的2倍。
约定取走最后一个石子的人为赢家,求必败态。
结论:当n为Fibonacci数的时为必败态。
即将斐波那契数列打表再判断n是否为斐波那契数判断即可
例题:HDU - 2516 取石子游戏
(我这里打表了,TIME是0 哦豁)
#include
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
long long feibonaq[100]={
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765,
10946,
17711,
28657,
46368,
75025,
121393,
196418,
317811,
514229,
832040,
1346269,
2178309,
3524578,
5702887,
9227465,
14930352,
24157817,
39088169,
63245986,
102334155,
165580141,
267914296,
433494437,
701408733,
1134903170,
1836311903,
2971215073,
4807526976,
7778742049,
12586269025,
20365011074,
32951280099,
53316291173,
86267571272,
139583862445,
225851433717,
365435296162,
591286729879,
956722026041,
1548008755920,
2504730781961,
4052739537881,
6557470319842,
10610209857723,
17167680177565,
27777890035288,
44945570212853,
72723460248141,
117669030460994,
190392490709135,
308061521170129,
498454011879264,
806515533049393,
1304969544928657,
2111485077978050,
3416454622906707,
5527939700884757,
8944394323791464,
14472334024676221,
23416728348467685,
37889062373143906,
61305790721611591,
99194853094755497,
160500643816367088,
259695496911122585,
420196140727489673,
679891637638612258,
1100087778366101931,
1779979416004714189,
2880067194370816120,
4660046610375530309,
7540113804746346429};
int main() {
ios::sync_with_stdio(false);
ll n;
while(~scanf("%lld",&n)) {
if(n==0) break;
int flag=0;
if(n<=2971215073) {
for(int i=1;i<=45;i++) {
if(n
巴什博弈
只有一堆n个物品,两个人轮流从中取物,规定每次最少取一个,最多取m个,最后取光者为胜。
结论:一轮最多拿的就是1+m个,所以控制下去,最后的不到(1+m)的物品肯定会被后手拿到的。
即判断n能不能除尽m+1,如若能则后手必胜
例题:HDU - 1846 Brave Game
#include
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
//如果m+1>=n,则后手必胜,说明当是这种情况的倍数时,后手能够一直制作出这种情况,则后手必胜
if(n%(m+1)==0) cout<<"second"<
尼姆博弈
有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。
结论:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。
例题:POJ - 2234 Matches Game
#include
//#include
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int k[100];
int main() {
ios::sync_with_stdio(false);
int n;
while(cin>>n) {
int tmp=0;
for(int i=0;i>k[i];
tmp^=k[i];
}
if(tmp==0) cout<<"No"<
乘法博弈
2 个人玩游戏,从 1 开始,轮流对数进行累乘,直到超过一个指定的值m时,该玩家获胜。
如果乘数范围是2~n,
则如果m为2~n,则先手必胜。
如果是n+1~2×(上一个后范围),则后手必胜,因为无论第一次先手乘的数是什么,数必在2到n之间
结论:必胜态对称,于是将m不断除与2n,判断余数在2到n还是n+1到2n之间即可
例题:POJ - 2505 A multiplication game
#include
//#include
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
long double n;
while(cin>>n) {
while(n>18) {
n/=2;
n/=9;
}
if(n<=9) cout<<"Stan wins."<
环形博弈
n个石子围成一个环,每次取一个或者取相邻的2个。
证明:以后再写(
结论:石子数目小于等于2 先手胜,其他 后手胜。
例题:POJ - 2484 A Funny Game
#include
//#include
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int n;
while(cin>>n&&n!=0) {
if(n<=2) cout<<"Alice"<
对称博弈
n个石子围成环,每次只能取相邻的1 - k个
结论:如果k
如果k>=n:先手赢
例题:HDU - 3951 Coin Game
#include
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int t;
cin>>t;
for(int i=1;i<=t;i++) {
int n,k;
cin>>n>>k;
cout<<"Case "<
威佐夫博弈
有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。
结论:看两个数的差值t是不是满足 (sqrt(5)+1)/2*t==min(n1,n2);,是的话则后手必胜
例题:HDU - 1527 取石子游戏
#include
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int a,b;
double temp;
while(cin>>a>>b) {
if(a>b) swap(a,b);
temp=floor((b-a)*(1+sqrt(5.0))/2.0);
if(temp==a) cout<<0<