試題 算法提高 第二點五個不高興的小明(dp)


問題描述
  有一條長為n的走廊,小明站在走廊的一端,每次可以跳過不超過p格,每格都有一個權值wi。
  小明要從一端跳到另一端,不能回跳,正好跳t次,請問他跳過的方格的權值和最大是多少?
輸入格式
  輸入的第一行包含兩個整數n, p, t,表示走廊的長度,小明每次跳躍的最長距離和小明跳的次數。
  接下來n個整數,表示走廊每個位置的權值。
輸出格式
  輸出一個整數。表示小明跳過的方格的權值和的最大值。
樣例輸入
8 5 3
3 4 -1 -100 1 8 7 6
樣例輸出
12
數據規模和約定
  1<=n, p, t<=1000, -1000<=wi<=1000。
思路
dp[i][j]代表第i位置跳到目標位置消耗j次跳的最大權值,倒數的后p+1個可以一步跳到一端,所以初始化dp[i][1]=w[i];
從后往前遞推,最后輸出dp[0][t]即是所求答案。p可能比n大,注意數組越界。
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll w[1005];
ll dp[1005][1005];
ll n,p,t;
const ll inf=0x3f3f3f;
int main(){
    cin>>n>>p>>t;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=n;i>=n-p&&i>=0;i--)dp[i][1]=w[i];///目標即是達到跳數為1時達到這些點
    for(int i=n;i>=0;i--){
        for(int j=2;j<=t;j++){///最后到達剩余1次跳數的格子
            dp[i][j]=-inf;///先置為無法到達(跳數過多or跳數過少)
            for(int k=1;k<=p&&i+k<=n;k++){
                dp[i][j]=max(dp[i][j],dp[i+k][j-1]);
            }
            if(dp[i][j]!=-inf)dp[i][j]+=w[i];///如果可以到達,加上本身的格子
        }
    }
    cout<<dp[0][t]<<endl;///從0位置花費t次到達另一邊
    return 0;
}

也可以記憶化搜索

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll w[1005];
ll dp[1005][1005];
ll n,p,t;
const ll inf=0x3f3f3f;
ll maxx=-inf;
int dfs(int m,int step){
    if(m>n+1||step<0)return -inf;///超過位置or步數不足
    if(step>n+1-m)return -inf;///剪枝,步數過多
    if(dp[m][step]!=-1)return dp[m][step];///更新過最優值,直接返回
    if(step==1){///剩余1步時
        if(n-m<=p)return dp[m][step]=w[m];///m跳到另一端小於等於p格
        else return -inf;///返回不可達
    }
    int sum=-inf;
    for(int i=1;i<=p;i++){
        sum=max(sum,dfs(m+i,step-1));
    }
    if(sum!=inf)sum+=w[m];///加上本身的權值
    return dp[m][step]=sum;
}
int main(){
    cin>>n>>p>>t;
    memset(dp,-1,sizeof(dp));
    for(int i=1;i<=n;i++)cin>>w[i];
    cout<<dfs(0,t)<<endl;
    return 0;
}

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM