1. 程式人生 > >【NOJ1084】【演算法實驗四】【DP_動態規劃】花生米(三)

【NOJ1084】【演算法實驗四】【DP_動態規劃】花生米(三)

1084.花生米(三)

時限:1000ms 記憶體限制:10000K  總時限:3000ms

描述

五一長假第三天,Tom和Jerry在倉庫散步的時候又發現了一堆花生米(倉庫,又見倉庫……)。這次Tom制定分花生米規則如下: 
???????1、Tom和Jerry輪流從堆中取出k粒花生米吃掉; 
2、第一次取花生米的人只能取一粒,以後取花生米的數量不能超過前一個人取花生米數量的兩倍; 
3、為顯示規則的公平性,Jerry可以選擇先取或者後取。 
Jerry當然還是希望最後一粒花生米被Tom吃掉。請計算,Jerry為了達到目的應該先取還是後取。

 

輸入

本題有多個測例,每個測例的輸入是一個整數n,n大於零小於等於1000,代表花生米的數量。
n等於0表示輸入結束,不需要處理。

 

輸出

每個測例在單獨的一行內輸出一個整數:Jerry先取輸出1;Tom先取輸出0。 


#include <iostream>
#include <cmath>

using namespace std;

int n;

int isWin[1001][1001];

int dp(int x, int k);

int main()
{
    for(int i=0; i<=1000; i++)
    {
        for(int j=0; j<=1000; j++)
        {
            isWin[i][j]=-1;
        }
    }
    while(cin>>n&&n)
    {
        cout<<dp(n, 1)<<endl;
    }
    return 0;
}

int dp(int x, int k)    //當前有x顆,最多能取k顆
{
    if(x==1)
    {
        isWin[x][k]=0;    //只剩1顆時,先取必輸
        return isWin[x][k];
    }
    else if(isWin[x][k]>=0)    //備忘錄中已有,直接返回
    {
        return isWin[x][k];
    }
    else
    {
        int mul=1;
        for(int i=1; i<=x&&i<=k; i++)    //從拿1顆到拿k顆中遍歷
        {
            isWin[x-i][min(x, 2*i)]=dp(x-i, min(x, 2*i));
            mul*=isWin[x-i][min(x, 2*i)];     //但凡拿完i顆後,別人先取必輸;
            if(mul==0)                        //則自己拿這i顆之前是必贏的
            {
                break;
            }
        }
        isWin[x][k]=1-mul;
        return isWin[x][k];
    }
}