1. 程式人生 > 實用技巧 >Nim plus Gym - 102878G(博弈題,dp做法(類似揹包))

Nim plus Gym - 102878G(博弈題,dp做法(類似揹包))

題意:倆個人,總共有n個球,每個人每次只能拿a[i]個球,每個人分別有m 個a[i],題目保證a[i]單調遞增,當誰不能拿球的時候他就輸了。
題目:https://vjudge.net/contest/413430#problem/G

題解: 一位大佬朋友寫的程式碼,本菜雞隻是理解後翻譯了一下。
這裡的dpl和dpm的值只有0和1,代表桌子上剩餘i個球的時候,這個時候誰去拿,他是會輸還是會贏,所以會有dpl[i]=dpm[i]的情況,這個時候誰去拿誰都能保證自己贏,就看誰先手了,因為龍龍是先手,所以這種情況龍龍一定會贏。else if(dpm[i-lo[j]]==0)這裡進行判斷的時候,i-lo[j]是一定比i小的,這個時候毛毛是贏還是輸的狀態是已經被判斷過的,所以這麼一直遞推下去,就會有結果。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;

int lo[120];//表示longlong每次能夠拿的球
int ma[120];//表示maomao每次能夠拿的球
int dpl[5100];//只有1和0倆個值,剩餘i個球的時候,這個時候龍龍去拿是輸還是贏
int dpm[5100];//只有1和0倆個值,剩餘i個球的時候,這個時候毛毛去拿是輸還是贏

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1; i<=m; i++)
    {
        cin
>>lo[i]; } for(int i=1; i<=m; i++) { cin>>ma[i]; } for(int i=1; i<=n; i++) //從1到n分別列舉剩i個球的時候這個時候誰去拿誰是輸還是贏, { int flag=0; //為0的時候代表這個時候誰去拿誰輸 for(int j=1; j<=m; j++)//遍歷龍龍能夠拿的數量 { if(lo[j]>i)//當它拿的數量大於剩餘的球的時候break {
break; } //剩餘i個球,這個時候龍龍如果拿走lo[j]個後,剩餘的球毛毛去拿會不會輸, else if(dpm[i-lo[j]]==0)//如果會的話,那麼就跳出,i這個時候龍龍去拿,龍龍就贏 { //這個時候可能毛毛去拿,毛毛贏,那麼遍歷龍龍可以去拿的每一種情況,如果每一種情況,毛毛都可以贏 flag=1//那麼剩餘i的時候龍龍去拿,龍龍就輸了,如果存在一個毛毛輸的情況,那麼龍龍就走這種情況,龍龍就贏 break; } } if(flag==1)dpl[i]=1;//如果龍龍可以贏,就標記龍龍贏 flag=0; for(int j=1; j<=m; j++) //這裡和上面龍龍的情況一樣,只不過是換了個人 { if(ma[j]>i) { break; }//遍歷毛毛拿走ma[j]個球后,龍龍是否輸,如果有一種情況是龍龍輸了,那麼在剩餘i個球的時候 else if(dpl[i-ma[j]]==0)//毛毛去拿,毛毛就可以贏,否則毛毛就輸 { flag=1; break; } } if(flag==1)dpm[i]=1; } //因為龍龍是先手,看一下桌子上剩餘n個球的時候,龍龍去拿是輸還是贏 if(dpl[n])printf("Long Long nb!\n"); else printf("Mao Mao nb!\n"); return 0; }