POJ 1740 博弈

题意

传送门 POJ 1740 A New Stone Game

题解

博弈问题,考虑 g r u n d y grundy grundy 数,但每一轮除了选择一堆石子移除至少一颗石子外,其余石子还可以任意转移到其他石子数非零的堆中,状态转移数过多。需要寻找其他方法判断胜负态。

在这类游戏当中,做出对称的状态再完全模仿对手的策略常常是有效的。

取走最后一堆石子的一方获胜,那么此时必胜态为仅剩一堆石子的状态。考虑 N i m Nim Nim 的异或运算构造必胜态,可以发现甚至无法通过样例。考虑石子堆的奇偶性,当石子堆中石子出现的个数为偶数,那么后手的一方可以模仿先手的策略使状态回到偶数情况。有以下结论成立:
相 同 石 子 数 的 堆 的 个 数 都 为 偶 数 → 必 胜 态 相同石子数的堆的个数都为偶数\rightarrow 必胜态 相 同 石 子 数 的 堆 的 个 数 存 在 奇 数 → 必 败 态 相同石子数的堆的个数存在奇数\rightarrow 必败态 简略地证明一下。首先一旦从偶数状态的某一堆移除至少一颗石子,则一定存在相同石子的堆个数为奇数。假设从石子数为 x i x_i xi 的一堆中移除了 a a a 个石子,分配了 b b b 个,分配给另一个 x i x_i xi e e e 个;此时原本石子数为 x i x_i xi 的一对堆被拆开,变为 ( x i + e , x i − a − b ) (x_i+e,x_i-a-b) (xi+e,xiab),无法通过分配 b b b 再次配成一对;反证法,在不产生新的奇数堆的情况下,假设能让 x i , x i − a − b x_i,x_i-a-b xi,xiab 都能与另一对 ( x j , x j ) (x_j,x_j) (xj,xj) 配成新的两对偶数堆,设分配的 b b b 个石子中有 c c c 个分配给某一个 x j x_j xj,有 d d d 偶数个分配给其余的偶数堆,那么有 x i + e = x j + b − c − d − e , x i − a − b = x j + c x_i+e=x_j+b-c-d-e,x_i-a-b=x_j+c xi+e=xj+bcde,xiab=xj+c,消去 x i , x j x_i,x_j xi,xj,得到 a + 2 c + d + 2 e = 0 a+2c+d+2e=0 a+2c+d+2e=0,与 a ≥ 1 a\geq 1 a1 矛盾。可以证实必败态只能转移到必胜态。

假设只存在个数为某个值 x i x_i xi 的石子堆为奇数堆,那么将其中一堆取完就可以将其转换为偶数态。若存在多个值的石子堆为奇数堆,对于每一个值只取一堆进行处理,此时剩余的堆为偶数状态;假设升序排序后要处理的堆石子值分别为 x 1 , x 2 … x n x_1,x_2\dots x_n x1,x2xn,根据差分的思想,有 x 1 + ( x 2 − x 1 ) + ⋯ + ( x n − x n − 1 ) = x n x_1+(x_2-x_1)+\dots+(x_n-x_{n-1})=x_n x1+(x2x1)++(xnxn1)=xn;若 n n n 为奇数,考虑到对于任意 i ∈ [ 1 , n ) i\in[1,n) i[1,n) x i + 1 − x i ≥ 1 x_{i+1}-x_i\geq 1 xi+1xi1,此时有 x n > ( x 2 − x 1 ) + ( x 4 − x 3 ) + ⋯ + ( x n − 1 − x n − 2 ) x_n>(x_2-x_1)+(x_4-x_3)+\dots+(x_{n-1}-x_{n-2}) xn>(x2x1)+(x4x3)++(xn1xn2),按顺序将 x n x_n xn 中的石子分配给括号中每一对中的较小值,其余石子都移除,即可转换为偶数状态;若 n n n 为偶数,此时有 x n > x 1 + ( x 3 − x 2 ) + ( x 5 − x 4 ) + ⋯ + ( x n − 1 − x n − 2 ) x_n>x_1+(x_3-x_2)+(x_5-x_4)+\dots+(x_{n-1}-x_{n-2}) xn>x1+(x3x2)+(x5x4)++(xn1xn2),按顺序将 x n x_n xn 中的石子分配给括号中每一对中的较小值,然后移除至少一颗石子使 x n x_n xn 变为 x 1 x_1 x1,即可转换为偶数状态。可以证实必胜态总是能转移到某个必败态。

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxp 100

int main()
{
    int n, cnt[maxp + 1];
    while (~scanf("%d", &n) && n)
    {
        memset(cnt, 0, sizeof(cnt));
        for (int i = 0; i < n; ++i)
        {
            int num;
            scanf("%d", &num);
            ++cnt[num];
        }
        int res = 0;
        for (int i = 1; i <= maxp; ++i)
        {
            if (cnt[i] & 1)
            {
                res = 1;
                break;
            }
        }
        printf("%d\n", res);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值