问题分析:
1.数据存储:二维数组data[maxn][maxn]存储树塔数据,dp[maxn][maxn]用来存储从某点出发的各个路径中的最优值
2.分析思路:树塔树塔问题自顶向下分析,自底向上计算。首先对倒数第二层的数据按照自顶向下的分析方法,两两结合选出最优解,然后再自顶向上逐层决策,然后逐层递推求出最终结果。
得出动态方程:dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + data[i][j],最后的结果保存在dp[0][0]中。
对于上面的数塔,我们的data数组如下:(图转自 https://blog.csdn.net/T_27080901/article/details/45801201)
dp数组状态如下:
不考虑路径输出源码如下:
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 101;
int n;
int data[maxn][maxn];
int dp[maxn][maxn];
int main()
{
int kase,i,j;
cin>>kase;
while(kase--)
{
cin>>n;
for(i=0;i<n;i++)
{
for(j=0;j<=i;j++)
{
cin>>data[i][j];
if(i==n-1)
dp[i][j]=data[i][j];
}
}
for(i=n-2;i>=0;i--)
for(j=0;j<=i;j++) //j的限制出错(不是j<i,而是j<=i),导致输出dp[0][0]为0
//dp[i][j] = dp[i+1][j]+dp[i+1][j+1]; //最初无脑写的动态方程
dp[i][j] = max(dp[i+1][j],dp[i+1][j+1])+data[i][j];
cout<<dp[0][0]<<endl;
}
return 0;
}
3.(额外考虑下)路径输出
1.利用递归函数打印
void print_ans(int i,int j)
{
cout<<data[i][j];
if(i<n-1) cout<<"-->";
if((dp[i][j]-data[i][j])==dp[i+1][j+1]) j++;
if(i>=n-1) return;
print_ans(i+1,j);
}
2.边自底向上计算边记录所做的决策
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 101;
int data[maxn][maxn];
int dp[maxn][maxn];
int path[maxn][maxn]; //初始化为0,0表示往左走,1表示往右走;
//int p[maxn]; //记录第i层的决策
//后来发现这个记录方法不行, 因为p会被覆盖
int main()
{
int kase,n,i,j;
cin>>kase;
while(kase--)
{
cin>>n;
for(i=0;i<n;i++)
{
for(j=0;j<=i;j++)
{
cin>>data[i][j];
if(i==n-1)
dp[i][j]=data[i][j];
}
}
for(i=n-2;i>=0;i--)
for(j=0;j<=i;j++)
if(dp[i+1][j]>dp[i+1][j+1]) //详细的决策步骤,边决策计算,边记录路径
{
dp[i][j] = dp[i+1][j]+data[i][j];
//p[i]=j;
}
else
{
dp[i][j] = dp[i+1][j+1]+data[i][j];
path[i][j]=1;
//p[i]=j+1;
}
cout<<dp[0][0]<<endl;
j=0;
for(i=0;i<=n-1;i++)
{
cout<<data[i][j];
j = j+path[i][j];
if(i<n-1) cout<<"-->";
}
/*for(i=0;i<=n-1;i++)
{
cout<<data[i][p[i]];
if(i<n-1) cout<<"-->";
}*/
}
return 0;
}
运行结果: