ACM-ICPC 2018 徐州賽區網路預賽 B. BE, GE or NE 記憶化搜尋
阿新 • • 發佈:2018-12-10
題意:
博弈,初始值為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; }