ACM-ICPC 2018 徐州赛区网络预赛 B. BE, GE or NE 记忆化搜索

版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/82721326

题目链接:https://nanti.jisuanke.com/t/31454

题意:

       博弈,初始值为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;
}

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/82721326