hdu1729

这是一道比较经典的博弈,但是我感觉题目说的不是很清楚:

1. There are n boxes; each box has its size. The box can hold up to s stones if the size is s.
2. At the beginning of the game, there are some stones in these boxes.
3. The players take turns choosing a box and put a number of stones into the box. The number mustn’t be great than the square of the number of stones before the player adds the stones. For example, the player can add 1 to 9 stones if there are 3 stones in the box. Of course, the total number of stones mustn’t be great than the size of the box.
4.Who can’t add stones any more will loss the game。

大意是:你有一些盒子,这些盒子有一个体积si,然后你和另一个人往里面放石子,盒子里面本来有一些石子,你和另外一个人轮流放的时候放的最多不能超过里面的石子的平方(比如里面原来有3个,那么你可以放的石子数量是1-9)当然了石子总数量不能超过其体积,最后不能放石子的输。

大家看看这句:The number mustn’t be great than the square of the number of stones before the player adds the stones。把它翻译过来就是数量不能超过原来数量的平方,在选手没有放石头之前。我的理解是他用的player 而不是players,这就是说石头的数量不能超过第一个选手放石头之前的数量的平方。当然这只是 我个人的理解。也可能是我想多了。

下面来分析一下:现在体积si,原来ci个石头,那么还可以放ki=si-ci个,

(1),那么如果说ci*ci>=ki,这就意味着可以一次性放完,那么SG呢?它的后续状态是ki-1(放一个石头),ki-2(放两个石头)...............0(放入ki个石头),明显0的sg为0,那么1的就是1..........最后ki-1的SG就是ki-1,所以ki的就是ki也就是si-ci。

(2),那么当ci*ci<ki会怎样呢?我们令t=sqrt(si*1.0),或者sqrt(si*1.0)+1我们知道的就是ci可不可以到达t的状态,因为

(si,t)这是一个必胜态,如果可以到达的话,我们就可以到达t-1状态,这就是一个必败态,当然了如果你直接研究t-1也是可以的,那么也就是说如果可以实现那么就可以知道他的SG,所以求(si,ci)的SG可以转化为求(t,ci)。那么就可以直接递归。

下面是一个AC代码:

#include<iostream>
using namespace std;
#include<stdio.h>
#include<cmath>
int mex(int n,int m)
{
    int t=(int)sqrt(n*1.0);
    while(t+t*t>=n)                        //当然这里可以做适当的调整。
        t--;
    if(m==t)return 0;
    else if(m>t)return n-m;
    else return mex(t,m);
}
int main()
{
    int s[55],c[55];
    int N,i,num,k=1;
    while(scanf("%d",&N)!=EOF,N)
    {
        num=0;
        for(i=0;i<N;i++)
            scanf("%d%d",&s[i],&c[i]);
        for(i=0;i<N;i++)
            if(s[i]==c[i]||c[i]==0||s[i]==0)                 //按照题目如果原来的石头是0也就是没有放,那么他在后面就一直不能放石头。
            continue;
        else num^=mex(s[i],c[i]);
        cout<<"Case "<<k<<":"<<endl;
        if(num==0)
            cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
        k++;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值