uva 10404 Bachet's Game

原题:
Bachet’s game is probably known to all but probably not by this name. Initially there are n stones on the table. There are two players Stan and Ollie, who move alternately.Stan always starts. The legal moves consist in removing at least one but not more than k stones from the table. The winner is the one to take the last stone.Here we consider a variation of this game. The number of stones that can be removed in a single move must be a member of a certain set of m numbers. Among the m numbers there is always 1 and thus the game never stalls.
Input
The input consists of a number of lines. Each line describes one game by a sequence of positive numbers.
The first number is n ≤ 1000000 the number of stones on the table; the second number is m ≤ 10
giving the number of numbers that follow; the last m numbers on the line specify how many stones can
be removed from the table in a single move.
Output
For each line of input, output one line saying either ‘Stan wins’ or ‘Ollie wins’ assuming that both
of them play perfectly.
Sample Input
20 3 1 3 8
21 3 1 3 8
22 3 1 3 8
23 3 1 3 8
1000000 10 1 23 38 11 7 5 4 8 3 13
999996 10 1 23 38 11 7 5 4 8 3 13
Sample Output
Stan wins
Stan wins
Ollie wins
Stan wins
Stan wins
Ollie wins
大意:
两个人玩取石子的游戏,现在给出一堆石子有n个,然后给你m个数表示每次可以拿走的石子数,拿走最后一枚石子的人获胜,每次stan先拿。问大家都用最优的拿法,谁是最后的赢家?

#include<iostream>
#include<algorithm>
#include<map>
#include<string>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<stack>
#include<queue>
#include<iomanip>
#include<set>
#include<fstream>
#include <climits>
using namespace std;
//fstream input,output;

bool dp[1000001];
int stone[11];
int n,tot;

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>tot)
    {
        memset(dp,false,sizeof(dp));
        dp[0]=false;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>stone[i];
        sort(stone+1,stone+1+n);
        for(int j=1;j<=tot;j++)
        {
            for(int i=1;i<=n&&j>=stone[i];i++)
            {
                if(!dp[j-stone[i]])
                {
                    dp[j]=true;
                    break;
                }
            }
        }
        if(dp[tot])
            cout<<"Stan wins"<<endl;
        else
            cout<<"Ollie wins"<<endl;
    }

解答:
刚看到这题寻思用sg函数解。不过看到标签里面写的是dp,一下就意识到是用完全背包的方法来解答。
设置dp[i]表示有i个石子的时候先拿石子的人是输是赢,如果是赢就标记为true,反之为false。
现在考虑拿石子游戏的规则,如果在当前状态i,也就是又i个石子的时候,如果你拿走一些石子后剩下的石子数中存在一个必败状态,也就是dp[i-stone[j]]中存在一个false,那当前dp[i]就应该是true。相反,如果dp[i-stone[j]]全是true,也就是无论你怎么石子,拿完以后的状态都是先手必胜,那必然是对手赢了,此时dp[i]=false。

这里说明一下遍历方式和完全背包的代码并不一样,应该先判断当前的石子数j里面拿走石子stone[i]的所有状态。所以,里层循环应该是stone。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值