P10111 [GESP202312 七级] 纸牌游戏 (决策路径DP)

Problem: P10111 [GESP202312 七级] 纸牌游戏

image


这是我一开始的DP思路:

每个格子 都由前一列的所有状态推导出来
如果在同一行,那么不消耗b[i]
如果不在同一行,消耗b[i]
然后每次操作都取最优值

但是不难发现,这是一个假的解法
因为对于样例1中
第一行第三列的最优解应该为25
这样子的话,第二行第四列的最优值就不会达到200+20-1
那么怎么办呢

于是我想到,多加一层
变成的是在dp[i][j][k]
其中
i:指的是对应的012操作
j:指的是对应的第N次
k:指的是当前消耗了第几个b值改变
那么dp[i][j][k]
就是指在消耗了第k个变换次数后的第j次的第i个手势中所能得到的最高分

因此推出公式:

if(p == 0)
{
    if(i == k)
        DPa[i][r][p] =max(DPa[i][r][p],DPa[k][r-1][p]+dpa[i][r][p]);
    else
    {
        if(i != k)
        DPa[i][r][p] = max(DPa[i][r][p],DPa[k][r-1][p-1]+dp[i][r]-b[p]);
        else
        {
            if(r-1 > p)   //如果是同一行传递,一定要注意前一个数字是否有对应的k值层
            DPa[i][r][p] = max(DPa[i][r][p],DPa[k][r-1][p]+dp[i][r]);
        }
    }
}
当时写的代码有点乱
r = j
p = k

其中 注意要将dp数组初始化为-INF,因为可能存在操作使得答案成为负数


Accepted Code:

//P10111 
#include <iostream>
#define ll long long
using namespace std;
ll a[1010],b[1010],c[1010];
ll dp[35][1010],Dp[35][1010],DPa[35][1010][1010],dpa[35][1010][1010];
int main()
{
    ll N;
    cin>>N;
    for(int i=1; i<=N; i++)
    {
        cin>>a[i];
    }
    for(int i=1; i<N; i++)
    {
        cin>>b[i];
    }
    for(int i=1; i<=N; i++)
    {
        cin>>c[i];
    }
    for(int i=0; i<=2; i++)
    {
        for(int r=1; r<=N; r++)
        {
            if(c[r] == 1)
            {
                if(i == 0) dp[i][r] = 0;
                if(i == 1) dp[i][r] = a[r];
                if(i == 2) dp[i][r] = 2*a[r];
            }
            if(c[r] == 2)
            {
                if(i == 1) dp[i][r] = 0;
                if(i == 2) dp[i][r] = a[r];
                if(i == 0) dp[i][r] = 2*a[r];
            }
            if(c[r] == 0)
            {
                if(i == 2) dp[i][r] = 0;
                if(i == 0) dp[i][r] = a[r];
                if(i == 1) dp[i][r] = 2*a[r];
            }
        }
    }
    for(int i=0; i<=2; i++)
    {
        for(int r=1; r<=N; r++)
        {
            for(int k=0; k<=N; k++)
            DPa[i][r][k] = -1e9;
            dpa[i][r][0] = dp[i][r];
            //cout<<dp[i][r]<<" ";
        }//cout<<endl;
    }
    for(int r=1; r<=N; r++)
    {
        for(int i=0; i<=2; i++)
        {
            //Dp[i][r]
            for(int k=0; k<=2; k++)
            {
                for(int p=0; p<r; p++)
                {
                    if(p == 0)
                    {
                        if(i == k)
                        {
                            DPa[i][r][p] =max(DPa[i][r][p],DPa[k][r-1][p]+dpa[i][r][p]);
                            //cout<<"p == 0 r i k p:"<<r<<" "<<i<<" "<<k<<" "<<p<<" "<<DPa[i][r][p]<<endl;
                        }
                    }
                    else
                    {
                        if(i != k)
                        {
                            
                            //if(r-1 >= p)
                            DPa[i][r][p] = max(DPa[i][r][p],DPa[k][r-1][p-1]+dp[i][r]-b[p]);
                            //cout<<"i != k r i k p:"<<r<<" "<<i<<" "<<k<<" "<<p<<" "<<DPa[i][r][p]<<endl;
                        }
                        else
                        {
                            
                            if(r-1 > p)
                            {
                                DPa[i][r][p] = max(DPa[i][r][p],DPa[k][r-1][p]+dp[i][r]);
                                //cout<<"i == k r i k p:"<<r<<" "<<i<<" "<<k<<" "<<p<<" "<<DPa[i][r][p]<<endl;
                            }
                        }
                    }
                    
                }
            }
        }
    }
    ll Max = 0;
    for(int i=0; i<=2; i++)
    {
        for(int r=1; r<=N; r++)
        {
            for(int k=0; k<=N; k++)
            Max = max(Max,DPa[i][r][k]);
            //cout<<DPa[i][r]<<" ";
        } //cout<<endl;
    }
    cout<<Max;
    return 0;
}

励志故事:
image

posted @ 2025-04-27 14:25  Supian_owo  阅读(75)  评论(0)    收藏  举报