简单博弈论—— URAL1087 取石子问题升级版

URAL1087 The Time to Take Stones

取石子问题升级版

Description
You probably know the game where two players in turns take 1 to 3 stones from a pile. Looses the one who takes the last stone. We’ll generalize this well known game. Assume that both of the players can take not 1, 2 or 3 stones, but k1, k2, …, km ones. Again we’ll be interested in one question: who wins in the perfect game. It is guaranteed that it is possible to make next move irrespective to already made moves.
Input
The first line contains two integers: n and m ( 1 ≤ n ≤ 10000; 1 ≤ m ≤ 50 ) — they are an initial amount of stones in the pile and an amount of numbers k1, …, km. The second line consists of the numbers k1, …, km, separated with a space ( 1 ≤ ki ≤ n).
Output
Output 1, if the first player (the first to take stones) wins in a perfect game. Otherwise, output 2.
Sample Input
input
17 3
1 3 4
output
2
题目大意:有两个人取石子,先手是编号为1的人,取到最后那个石子的人就输了。输入石子个数n,有m种取法。再输入每种取法分别能取多少个石子。输出赢的那个人的编号(1或者2)。

其实,做法是类似于DP的(其实就是)。
首先考虑一个问题,如果这堆石子只有一个。那么先手会赢吗?(显然是输家)。
再考虑一个问题:如果现在已经知道在剩余a个石子时取,先手一定会输,那么假设b是那m种选法中任意一种,对于a+b个石子,先手的胜负情况可以确定吗?
答案是显然会赢。
为了方便表示,用1和0表示先手的胜和负。
再考虑一个命题:如果现在已经知道在剩余a个石子时取,先手的胜负情况是f,那么假设b是那m种选法中任意一种,对于a+b个石子,先手的胜负情况一定是f^1。

这是显然的。

那么,我们的dp状态转移方程已经差不多了。
直接看代码吧:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
int f[10010],a[100];
int main(){
    int i,j,k,m,n;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)scanf("%d",a+i);
    f[1]=0;//如果只剩1个石子,显然先手会输
    for(i=2;i<=n;i++){//计算剩余石子为2~n的情况
        f[i]=0;//假设全都会输
        for(j=1;j<=m;j++)
            if( (i-a[j]>0)&&(f[i-a[j]]==0) ){//仔细琢磨就会发现其实这就是上面那个命题
                f[i]=1;//如果会赢,就不用再算了
                break;
            }
        }
    printf("%d\n",f[n]==1?1:2);//根据先手(1)的胜负情况输出
    return 0;
}

是不是很简单的啊~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值