阶梯博弈

in 知识点 with 0 comment

阶梯博弈

阶梯博弈也是博弈论中重要的一个分支,所谓阶梯博弈,其实指代的是一类只能从后向前逐层传递石子的游戏的模型,同样的,这类问题也可以转化成NIM取石子问题求解

前五堆石子分别有2,1,3,1,4个石子,每个人只能把后面的任意多个石子向前移,不能移动者为负,现在问先手必胜还是必败?

这个很简单,分别把五堆石子编号0~4,很显然当把所有石子移到0堆的一方获胜,即对应先手必胜态。不考虑编号后的奇数堆(可以假设奇数堆上没有石子可以移动),对于所有偶数堆,率先移动的一方肯定会失败,这是显然的,因为目标堆是第0堆,而移动2k堆只能到2k-1堆,即奇数堆,另一方再次移动又会回到偶数堆的情况,如此往复,最终一定是面对均为偶数堆的一方失败,这样看来,偶数堆对胜负的影响可以转化为哪一方先将所有奇数堆移动完即可取得胜利。有了这样的转化,问题就迎刃而解了,因为每次可以移动任意多个,所以从奇数堆移到偶数堆就可以等效成取走奇数堆中的石子,这个问题很熟悉,不就是NIM取石子问题么!只要对奇数堆的石子做NIM取石子问题便可求解原问题。如果对手不对奇数堆移动,而选择移动偶数(2k)堆到第2k-1堆,方法同样很简单,你只需要以其人之道还治其人之身,把他移动的相等数量的石子再从2k-1堆移动到2k-2堆,这样等效于又回到了原来的局面。

P3480 [POI2009]KAM-Pebbles

Description

有N堆石子,除了第一堆外,每堆石子个数都不少于前一堆的石子个数。两人轮流操作每次操作可以从一堆石子中移走任意多石子,但是要保证操作后仍然满足初始时的条件谁没有石子可移时输掉游戏。问先手是否必胜。

Solution

对于任意一个堆进行符合要求的取石子操作后,易知:它与后一个堆的石子差增加,而与前一个堆的石子差减小(一定注意前后的增减情况,这会影响阶梯博弈的方向!),而增减的幅度相同,这就等效于把前面的石子向相邻右侧移动了一位,即可以转化为将原数组的差分数组进行一次阶梯博弈,原问题即可求解!

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1010;
int cnt;
int a[maxn],M[maxn];

int main()
{
    scanf("%d",&cnt);
    while(cnt--)
    {
        int n,xorsum;
        scanf("%d",&n);
        a[0]=0;
        xorsum=0;
        for(int i=1;i<=n;++i)
          scanf("%d",&a[i]);
        for(int i=1;i<=n;++i)
          M[i]=a[n-i+1]-a[n-i];
        for(int i=1;i<=n;i+=2)
          xorsum^=M[i];
        if(xorsum) printf("TAK\n");
        else printf("NIE\n");
    }
    return 0;
}

扫描二维码,在手机上阅读!
Responses