【问题描述】
给定一个数塔,如下图所示。在此数塔中,从顶部出发,在每一节点可以选择走左下或右下,一直走到底层。请找出一条路径,使路径上的数值和最大。
9 | ||||||||
12 | 15 | |||||||
10 | 6 | 8 | ||||||
2 | 18 | 9 | 5 | |||||
19 | 7 | 10 | 4 | 16 |
【输入形式】
输入时第一行一个整数n,表示该数塔的行数,其余n行表示该塔每行的数值
【输出形式】
输出包含两行,第一行为最大路径上的数值之和, 第二行n个数字为从上而下最大路径数值
【样例输入】
5
9
12 15
10 6 8
2 18 9 5
19 7 10 4 16
【样例输出】
59
9 12 10 18 10
【思路】
一道基本的动态规划题。我用的是递归求解,没有建二维数组(所以保存路径有亿点点麻烦)
有点类似于满二叉树的储存方法,用一个一维数组储存整个数塔,顶点编号为0,层数为1;
这样子,每个点的左右子节点就是它(自身编号+层数)或者(自身编号+层数+1)
记录路径:path数组在递归时储存【最大值路径】中每层所选择的子结点,一个接一个地输出来就行~
【AC代码】
#include<string>
#include<iostream>
#include<sstream>
#include<stack>
using namespace std;
int a[100010];
int path[100010]; //前导数组,用来寻找最长路径
int n; //最大层数
int dp(int now,int now_floor,int fa){
if(now_floor==n) { //到达最底层
return a[now];
}
int left=a[now] + dp( now+now_floor,now_floor+1, now);
int right=a[now]+ dp(now+now_floor+1, now_floor+1, now);
path[now]=left>right?now+now_floor:now+now_floor+1;
return max(left,right);
//对比走左右两边,哪边更大。左边:结点+层数 右边:结点+层数+1
}
int main(){
cin>>n;
int num=((n+1)*n)/2; //总的结点数量
for(int i=0;i<num;i++) cin>>a[i];
cout<<dp(0 , 1 , -1)<<'\n'; //当前总和为a[0],初始结点为0,初始层数为1
int k=0;
int f=1;
while(f<=n){
cout<<a[k]<<" ";
k=path[k];
f++;
}
}
【写在后面】
觉得对你有帮助的话记得一键三连哦~(误
相关题目放在了【HNU CJ】专栏
如果有啥问题可以评论留言或者私我哦~