题目
下图是个数字三角,请编写一个程序计算从顶部至底部某处一条路径,使得该路径所经过的数字总和最大。
7
3 8
8 1 0
2 7 4 4
1. 每一步可沿左斜线向下或右斜线向下走;
2. 1<=三角形行数<=100
3. 三角形中的数字为整数 0,1,……,99。
4. 如果有多种情况结果都最大,任意输出一种即可。
输入:
第一行一个整数N,代表三角形的行数。
接下来N行,描述了一个数字三角。
输出:
第一行一个整数,代表路径所经过底数字总和。
第二行N个数,代表所经过的数字。
样例
输入:
4
7
3 8
8 1 0
2 7 4 4
输出:
25
7 3 8 7
分析:该问题有两个要求——输出最大总和与相应路径。若直接计算各种路径则计算量巨大,若直接利用递归【 best(a[i],a[j]) { return a[i][j]+max{best(i+1,j),best(i+1,j+1)}】则会超时,且不好记录路径。于是应利用动态规划将问题分解,需要两个二维数组,分别记录对应每个节点上的和与路径。
思路一:总体方向:由上而下收。目标范围:顶两层。较低一层的每个数字分别选加上游较大的数字,数字和存在较低一层的数字中。目标下移一层,原下游变为上游。最终底层存储了各路径的数字总和,选择最大的。
思路二:总体方向:由下而上收。目标范围:底两层。较高一层的每个数字分别选加下游较大的数字,数字和存在较高一层的数字中。目标上移一层,原上游变为下游,最终顶层存储了最大数字总和。
思路一代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,ans=1,dp[105][105],arr[105][105],path[105][105];
//arr存数字金字塔,dp存数字之和(注释代码方便查看),path记路径
void print(int i,int j);
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
scanf("%d",&arr[i][j]);
dp[1][1]=arr[1][1];
for(int i=2;i<=n;++i)
for(int j=1;j<=i;++j)
//下游选加上游中较大的 ,和存在dp相应位置中 ,上一节点的位置存在path中
if(dp[i-1][j]>dp[i-1][j-1])
dp[i][j]=dp[i-1][j]+arr[i][j],path[i][j]=j;
else
dp[i][j]=dp[i-1][j-1]+arr[i][j],path[i][j]=j-1;
/* for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j)
printf("%d ",dp[i][j]);
printf("\n");
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j)
printf("%d ",path[i][j]);
printf("\n");
}
*/
for(int i=1;i<=n;++i)
if(dp[n][ans]<dp[n][i])
ans=i;//ans标记a[n]最大值
printf("%d\n",dp[n][ans]);
print(n-1,path[n][ans]);
printf("%d\n",arr[n][ans]);
ans=1;
memset(dp,0,sizeof dp);
}
return 0;
}
//递归回溯路径
void print(int i,int j){
if(i!=1)
print(i-1,path[i][j]);
printf("%d ",arr[i][j]);
}
思路二代码:
#include<stdio.h>
#define maxn 102
int a[maxn][maxn],p[maxn]={0};
int main()
{
int n,i,j,u,b;
long sum=0;
scanf("%d",&n);
for(i=0;i<n;i++)
for(j=0;j<=i;j++)
scanf("%d",&a[i][j]);
for(i=n-2;i>=0;i--)
for(j=0;j<=i;j++)
{a[i][j]+=a[i+1][j]<a[i+1][j+1]? a[i+1][j+1]:a[i+1][j];}
printf("%d\n",a[0][0]);
j=0;
for(i=0;i<n;i++)
{
if(a[i+1][j]<a[i+1][j+1]) b=j+1;
else b=j;
p[i]=a[i][j]-a[i+1][b];
j=b;
}
for(i=0;i<n;i++)
{
if(i) printf(" ");
printf("%d",p[i]);
}
return 0;
}