一、Bash博弈

1、问题模型:只有一堆n个物品,两人轮流从这堆物品中取物,最多取m个,最后取光者胜。

2、解决思路:当n=m+1时,由于一次最多取m个,无论先取者拿走多少个,后取者都能一次拿走剩余的物品,后者取胜,所以当一方面对n%(m+1)==0的时候,其面临的是必败局势。所以当n==(n+1)*r+s(r为任意自然数,s<=m)时,如果先取者要拿走s个物品,后取者拿走x(x<=m)个物品,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保留给对手留下(m+1)的倍数,就能最后获胜。

3、变形:条件不变,改为最后取光的人输。

解决方法:当(n-1)%(m+1)==0时,后手胜利。

例题:Bash的游戏

#define _MAX 10000
int a[_MAX];
int b[_MAX]; int bash(int N, int K)
{
if (N % (K + 1) == 0)
{
return 2;
}
return 1;
} int main()
{
int T;
scanf("%d", &T);
for (int i = 0; i < T; i++)
{
scanf("%d%d", a + i, b + i);
}
for (int i = 0; i < T; i++)
{
if (bash(a[i], b[i]) == 1)
{
printf("A\n");
}
else
{
printf("B\n");
}
}
return 0;
}

二、威佐夫博弈

1、问题模型:有两堆各若干个物品,两个人轮流从某一堆或同时从两堆取出同样多的物品,规定每次取出一个,多者不限,最后取光者得胜。

2、解决思路:A:设(ai,bi)(ai<=bi,i=0,1,2,3.....,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲输了,这种局势我们称为其一局势。

奇异局势的前几项是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)

任给一个局势(a,b),如下公式判断它是不是奇异局势:

ak =[k(1+√5)/2],bk= ak + k  (k=0,1,2,…,n 方括号表示取整函数)。(证明见百度百科)也就是黄金分割点。

3、满足上述公式的局势性质:

(1)任何自然数都包含在一个且仅有一个奇异局势中。

(2)任何操作都可以把奇异局势变为非奇异局势。

若只改变奇异局势(ak,bk)的某一个分量,那么另一个分量不可能在其他奇异局势中,所以必然是非奇异局势。

(3)采用适当的方法,可以将非奇异局势变为奇异局势。

假设面对的局势是(a,b),若 b = a,则同时从两堆中取走 a 个物体,就变为了奇异局势(0,0);如果a = ak ,b > bk,那么,取走b  – bk个物体,即变      为奇异局势;如果 a = ak ,  b < bk ,则同时从两堆中拿走 ak – ab – ak个物体,变为奇异局势( ab – ak , ab – ak+ b – ak);如果a > ak ,
           b= ak + k,则从第一堆中拿走多余的数量a – ak 即可;如果a < ak ,b= ak + k,分两种情况,第一种,a=aj (j < k),从第二堆里面拿走 b – bj 即可; 第      二种,a=bj (j < k),从第二堆里面拿走 b – aj 即可。

4、结论

两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,后拿者必胜。

例题:威佐夫博弈

int main()
{
int t, a, b, m, k;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &a, &b);
if (a > b)
{
a ^= b;
b ^= a;
a ^= b;
}
m = b - a;
k = (int)(m * (1 + sqrt(5)) / 2.0);
//m = ? * a
//k = m / ?
//?:黄金分割数
//如果a == k,则为后手赢,否则先手赢(奇异局)
printf("%s\n", a == k ? "B" : "A");
}
return 0;
}

威佐夫博弈 V2(大数)


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
LL tmp[3] = {618033988,749894848,204586834};
LL MOD = 1000000000;
int main()
{
int T;
LL m, n;
cin>>T;
while(T--)
{
cin>>m>>n;
if(m < n)
swap(n, m);
LL cha = m - n;
LL ta = cha/MOD, tb = cha%MOD;
LL tp = tb*tmp[2];
tp = ta*tmp[2] + tb*tmp[1] + tp/MOD;
tp = ta*tmp[1] + tb*tmp[0] + tp/MOD;
tp = cha + ta*tmp[0] + tp/MOD;
if(tp == n)
puts("B");
else
puts("A");
}
return 0;
}





三、Nim博弈

1、问题模型:有三堆各若干个物品,两个人轮流从某一堆取人一多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

2、解决思路:

用(a,b,c)表示某种局势,显然(0,0,0)是第一种局势,无论谁面对奇异局势,都必然失败。

第二种是(0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0)。

搞定这个问题必须把必败态炸出:(a,b,c)是必败态等价于a^b^c==0(^表示异或运算)

3、推广:

如果我们面对的是一个非奇异局势(a,b,c),那么如何变成奇异局势呢?

假设a<b<c,我们只要将c变成a^b即可,因为a^b^(a^b)=(a^a)^(b^b)=0^0=0。要将c变成a^b,只要c-(a^b)。

例题:Nim的游戏

int main(int argc, const char * argv[])
{
int N, stone, tag = 0;
scanf("%d", &N);
while (N--)
{
scanf("%d", &stone);
tag ^= stone;
}
//tag为0则为后手赢,否则为先手赢
printf("%c\n", tag == 0 ? 'B' : 'A');
return 0;
}

ACM博弈论总结的更多相关文章

  1. acm博弈论基础总结

    acm博弈论基础总结 常见博弈结论 Nim 问题:共有N堆石子,编号1..n,第i堆中有个a[i]个石子. 每一次操作Alice和Bob可以从任意一堆石子中取出任意数量的石子,至少取一颗,至多取出这一 ...

  2. ACM博弈论基础

    博弈论的题目有如下特点: 有两名选手 两名选手交替操作,每次一步,每步都在有限的合法集合中选取一种进行 在任何情况下,合法操作只取决于情况本身,与选手无关 游戏败北的条件为:当某位选手需要进行操作时, ...

  3. 博弈论入门小结 分类: ACM TYPE 2014-08-31 10:15 73人阅读 评论(0) 收藏

    文章原地址:http://blog.csdn.net/zhangxiang0125/article/details/6174639 博弈论:是二人或多人在平等的对局中各自利用对方的策略变换自己的对抗策 ...

  4. 湖南大学第十四届ACM程序设计新生杯(重现赛)I:II play with GG(博弈论||DP)

    链接:https://ac.nowcoder.com/acm/contest/338/I 来源:牛客网 题目描述 IG won the S championship and many people a ...

  5. ACM之路(17)—— 博弈论

    博弈论这方面网上资料庞大,我觉得我不可能写的比他们好,就转载一下我觉得写的不错的博客好了. 首先是三大博弈:巴什博奕,威佐夫博奕,尼姆博奕.博客:三大基本博弈. 然后是强大的sg函数和sg定理:SG. ...

  6. 【ACM】取石子 - 博弈论

    取石子(一) 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子.游 ...

  7. 【转】博弈论——acm

    转自http://blog.csdn.net/lgdblue/article/details/15809893 序:博弈是信息学和数学试题中常会出现的一种类型,算法灵活多变是其最大特点,而其中有一类试 ...

  8. ACM进阶计划

    ACM进阶计划ACM队不是为了一场比赛而存在的,为的是队员的整体提高.大学期间,ACM队队员必须要学好的课程有:lC/C++两种语言l高等数学l线性代数l数据结构l离散数学l数据库原理l操作系统原理l ...

  9. 收集一些关于OI/ACM的奇怪的东西……

    一.代码: 1.求逆元(原理貌似就是拓展欧几里得,要求MOD是素数): int inv(int a) { if(a == 1) return 1; return ((MOD - MOD / a) * ...

随机推荐

  1. hdu 1698区间延迟更新

    #include<stdio.h> #define N 100100 struct node { int x,y,yanchi; }a[N*4];//注意数组范围 void build(i ...

  2. 主席树初探--BZOJ1901: Zju2112 Dynamic Rankings

    n<=10000的序列做m<=10000个操作:单点修改,查区间第k小. 所谓的主席树也就是一个值域线段树嘛..不过在这里还是%%fotile 需要做一个区间查询,由于查第k小,需要一些能 ...

  3. Codeforces 645A Amity Assessment【八数码】

    题目链接: http://codeforces.com/problemset/problem/645/A 题意: 2*2的八数码问题 分析: 这题n为2,不需要搜索,直接判断字母排列顺序就好了. 注意 ...

  4. TCP/IP学习笔记(3)----IP,ARP,RARP协议

    把这三个协议放到一起学习是因为这三个协议处于同一层(网络层协议),ARP协议用来找到目标主机的Ethernet网卡Mac地址,IP则承载要发送的消息.数据链路层可以从ARP得到数据的传送信息,而从IP ...

  5. Ubuntu 16.04安装Memcached(单机)

    Ubuntu 16.04安装Memcached,不过不仅限与Ubuntu,可以用CentOS等去安装,只不过测试时使用的是Ubuntu机器.Windows下不建议使用,本机调试可以使用,线上环境除了W ...

  6. Linux 网络配置,ifconfig不显示ip地址的解决办法

    进入到/etc/sysconfig/network-scripts 然后设置虚拟机的网络配置 这样就配置成功了

  7. JSP处理日期

    以下内容引用自http://wiki.jikexueyuan.com/project/jsp/handling-date.html: 使用JSP的一个最重要的优点是,可以使用核心Java中所有有效的方 ...

  8. 自己构建的Lumbda表达式

    自己构建的Lumbda表达式 定义接口: package com.stono.lambda; public interface Add { public void add(int x, int y); ...

  9. Linux下完美使用find+grep实现全局代码搜索

    作者:zhanhailiang 日期:2014-10-11 背景 在Window下有大量方便的图形化工具能够实现全局搜索,可是Linuxserver中因为使用命令行操作导致全局搜索是一个比較高的门槛. ...

  10. 动态生成页面(一)——ASP.NET中Literal使用

    在页面中加入内容时,假设是静态内容.无需使用容器,能够直接将标记作为HTML直接加入到页面中:可是,假设是动态内容,则必须借助容器将内容加入到页面中.典型的容器有:Label控件.Literal控件. ...