1. 程式人生 > >ACM-ICPC 2018 徐州賽區網路預賽 B. BE, GE or NE 記憶化搜尋

ACM-ICPC 2018 徐州賽區網路預賽 B. BE, GE or NE 記憶化搜尋

題意:

       博弈,初始值為k,有兩個臨界值l和r,玩家p1希望n輪結束後值大於等於r,玩家p2希望結束後值小於等於l,每一輪有三個選擇 a b c,如果a不為0,那麼這輪進行的玩家可以在原有的值上加上a然後結束,如果b不為0,那麼這輪進行的玩家可以在原有的值上減去b然後結束,如果c不為0,那麼這輪進行的玩家可以把原有的值乘上-1然後結束,值的上限不得超過100,下限不得低於-100。問n輪後的值在哪個範圍,如果在r即以上輸出Good Ending,在l即以下輸出Bad Ending,在中間輸出Normal Ending。

做法:

       隊友有dp的思路但是最後把點想成了區間所以最後沒有做出來,而我把記憶化搜尋的第二維給想錯了所以也沒做出來,好不容易碰到一道我都能想的出來是記憶化搜尋的題目,結果還沒出來,真是氣死我了。

       咳咳,迴歸正題。我們dp的第一維當然是第i輪,第二維是分數為j的時候,dp[i][j]代表此時在哪個範圍。我原先想的是第二維為這個人選第j個操作時候的勝負,現在想想都肯定是錯的,當然腦子抽了。因為每一次進入迴圈的值已經不一樣了,所以這樣做肯定是有問題的。可是分數如果已經定下來了,相同的操作就不會有問題,這樣的複雜度最多就是1000*200了。好氣,題目還是要多做。 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int add=100;
int dp[1005][300],n,m,l,r,op[1005][5];
int dfs(int now,int cur){
    if(now==n+1){
        if(cur<=l) return 0;
        else if(cur<r) return 1;
        return 2;
    }
    if(dp[now][cur+add]!=-1) return dp[now][cur+add];
    if(now%2){
        int res=0;
        if(op[now][1]) res=max(res,dfs(now+1,min(100,cur+op[now][1])));
        if(op[now][2]) res=max(res,dfs(now+1,max(-100,cur-op[now][2])));
        if(op[now][3]) res=max(res,dfs(now+1,-cur));
        return dp[now][cur+add]=res;
    }
    else {
        int res=2;
        if(op[now][1]) res=min(res,dfs(now+1,min(100,cur+op[now][1])));
        if(op[now][2]) res=min(res,dfs(now+1,max(-100,cur-op[now][2])));
        if(op[now][3]) res=min(res,dfs(now+1,-cur));
        return dp[now][cur+add]=res;
    }
}
int main(){
    memset(dp,-1,sizeof(dp));
    scanf("%d%d%d%d",&n,&m,&r,&l);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=3;j++)
            scanf("%d",&op[i][j]);
    int ans=dfs(1,m);
    if(ans==2) printf("Good Ending\n");
    else if(ans==1) printf("Normal Ending\n");
    else printf("Bad Ending\n");
    return 0;
}