博弈,常见博弈算法

佐威夫博弈:

适用题型:
有两堆各若干个物品,两个人轮流从任意一堆中取出至少一个或者同时从两堆中
取出同样多的物品,规定每次至少取一个,至多不限,最后取光者胜利。
我们把先手必输的局势定义为“奇异局势”;
第一种(0,0)

第二种(1,2)

第三种(3,5)

第四种 (4 ,7)

第五种(6,10)

第六种 (8,13)

第七种 (9 , 15)

第八种 (11 ,18)

第n种 (a[k],b[k]) 每种奇异局势的第一个值(这里假设第一堆数目小于第二堆的数目)总是等于当前局势的差值乘上1.618
我们都知道0.618是黄金分割率。而威佐夫博弈正好是1.618,这就是博弈的奇妙之处
在编程题中,有些题目要求精度较高,我们可以用下述式子来表示这个值
1.618 = (sqrt(5.0) + 1) / 2
详解:点击这里

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
double p=(sqrt(5.0)+1)/2.0;//差值*1.618==minn(两堆中较小那堆的数量)
//若相等为奇异局势,先手必败 
void solve()
{
	double n,m,c;
	while(~scanf("%lf %lf",&n,&m))
	{
		c=(n-m)>0?n-m:m-n;
		n=n<m?n:m;
		if(int(c*p)==int(n))
			printf("0\n");
		else
			printf("1\n");
	}
}
int main()
{
	solve();
	return 0;
 } 

巴什博弈:

适用题型: 只有一堆n个物品,两个人轮流从这堆物品中取物, 规定每次至少取一个,最多取m个。最后取光者得胜。(必须是一堆才试用哦。)
我们不难发现如果我们起手面对的情况是(n+1)k(k=0,1,2…n)的情况就必输了,n就是最多可以拿的石子个数。 此时就属于奇异局,必败。
相反的,如果你不是处于奇异局,比如是(n+1)k+r,拿出r个石子,你的对手就进入奇异局,己方必胜;
详解:点击这里

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n, m;
    while (cin >> n >> m)//n:物品数目,m:最多取的个数
    {
        if (n % (m + 1) == 0)//必败,奇异局
            cout << "Send to you!" << endl;
        else //必胜
            cout << "I'm first!" << endl;
    }
    return 0;
}

尼姆博弈:

适用题型: 有若干堆石子,每堆石子的数量是有限的,二个人依次从这些石子堆中拿取任意的石子,至少一个(不能不取),最后一个拿光石子的人胜利。
用0与每个数异或,如最后结果为0,则后手胜(设一数组a[m],令sum=0,循环与数组每一个数据异或(sum^=a[i]),sum最后等于0则后手胜)
如果我们面对的是一个非必败态(a,b,c),要如何变为必败态呢?(XOR表示异或)
假设 a < b < c,我们只要将 c 变为a XOR b,即可。因为有如下的运算结果:
a XOR b XOR (a XOR b)=(a XOR a) XOR (b XOR b) = 0 XOR 0 = 0
要将c 变为a XOR b,只要对 c进行 c-(a XOR b)这样的运算即可
详解:点击这里

HDU - 2176
Problem Description m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子.例如5堆 5,7,8,9,10先取者胜,先取者第1次取时可以从有8个的那一堆取走7个剩下1个,也可以从有9个的中那一堆取走9个剩下0个,也可以从有10个的中那一堆取走7个剩下3个.

Input
输入有多组.每组第1行是m,m<=200000. 后面m个非零正整数.m=0退出.

Output
先取者负输出No.先取者胜输出Yes,然后输出先取者第1次取子的所有方法.如果从有a个石子的堆中取若干个后剩下b个后会胜就输出a b.参看Sample Output.

Sample Input

2
45 45
3
3 6 9
5
5 7 8 9 10
0

Sample Output

No
Yes
9 5
Yes
8 1
9 0
10 3

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int a[200001];
int main()
{
	int i,j,n,m,k;
	while(~scanf("%d",&n)&&n)
	{
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		m=a[0];
		for(i=1;i<n;i++)
		{
			m=m^a[i];
		}
		if(m==0)
			printf("No\n");
		else
		{
			printf("Yes\n");
			for(i=0;i<n;i++)
			{
				k=m^a[i];		//将异或得到的答案跟其中a[i]再异或一次就相当于把a[i]去除后
								//剩下的所有的异或得到的值,如果该值比a[i]小说明可以从a[i]
								//中去除一部分得到该值,两个相等的值异或便得到0,即可
				if(k<a[i])
					printf("%d %d\n",a[i],k);
			}
			
		}
	}
	return 0;
}

斐波那契博弈:

题型: 有一堆个数为n(n>=2)的石子,游戏双方轮流取石子,规则如下:

1)先手不能在第一次把所有的石子取完,至少取1颗;

2)之后每次可以取的石子数至少为1,至多为对手刚取的石子数的2倍。

约定取走最后一个石子的人为赢家。

结论:当n为斐波那契数的时候,先手必败。

f[i]:1,2,3,5,8,13,21,34,55,89……
详解:点击这里

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值