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

来源:互联网 发布:淘宝folk老王是正品吗 编辑:程序博客网 时间:2024/06/05 03:51

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;}

是不是很简单的啊~

0 0
原创粉丝点击