蓝桥算法提高 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。


思路:

本题需要选择一步的距离,在规定步数下,求最优解,所以有两种解法,DFS(记忆化) 和 DP。

DFS+记忆化

数据说明:

maxn是数据范围,  INF是最大值 (个人习惯)
n:一共多少个点   p:最远一步可以走多远    t:能走几步  
w[i] :点权      dp[i][j]  从i点还剩j步的最大值
index就是i  step就是j 

Code:

#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const ll INF = 0x7f;
const ll maxn = 1005; //数据范围

ll n,p,t;
ll w[maxn];
ll dp[maxn][maxn];

ll dfs(ll index,ll step){
    
     
	if(dp[index][step]!= -1)return dp[index][step]; //剪枝 
	if(step*p < n-index+1)return -INF; //太远 走不到
	if(step>n-index+1)return -INF;  //步数过多 
	if(step == 1){
    
       
		if(n-index+1 <= p) return dp[index][1]=w[index]; //只剩一步的情况下能走到 
		else return -INF; //不能走到 
	}else{
    
    
		ll sum = -INF;
		for(ll i=index+1;i<=index+p && i<=n;i++)sum = max(sum,dfs(i,step-1)); //下一步走多远 
		if(sum!= -INF)sum+=w[index]; //下一步多远没有计算此步的距离 
		return dp[index][step] = sum; //记忆 
	}
}
int main()
{
    
    
	cin>>n>>p>>t;
	for(int i=1;i<=n;i++)cin>>w[i];w[0]=0;
	memset(dp,-1,sizeof(dp));
	cout<<dfs( 0 , t)<<endl;  //从起点还有t步开始搜 
	return 0;
}

DP 动态规划

数据说明:

maxn是数据范围,  INF是最大值 (个人习惯)
n:一共多少个点   p:最远一步可以走多远    t:能走几步  
w[i] :点权      dp[i][j]  从i点还剩j步的最大值

思路:

①以为要求某个点到终点的最大值,所以我们应该从后往前递推 (第一层for)
②模拟能跳的次数 (第二层for)
③模拟跳跃的距离 (第三层for)
因为需要①,所以我们可以预处理只剩最后一步的情况,及终点向前移动p个位置点的初始值
接下来将每个点的值初始为 -INF 用于求最大值
dp[0][t]为答案

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x7f;
const int maxn = 1005;

ll n,p,t;
ll w[maxn]; //记录点的权值 
ll dp[maxn][maxn]; //dp[i][j] 从i点跳j次可以到达终点的最大值
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]; //预处理后面只需要跳一部的情况

	for(int i=n;i>=0;i--){
    
     //一共n站
		for(int j=2;j<=t;j++){
    
     //模拟可以跳的次数
			dp[i][j] = -INF;
			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; //初始站跳 t 次的最大值 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zhimeng_LQ/article/details/108808451