线性DP是动态规划问题中的一类问题,指状态之间有线性关系的动态规划问题。
动态规划的算法思想就是将待求解的问题分解成较小且相同子问题,最终产生整体最优解。
经典问题有数字三角形。
题目意思:
自上而下走,每次只能向左下或者右下,找出计算之和最大值输出。
解析:
自下而上,更改每次的状态——最大值(子问题),求出每个位置的最大值,最终得出第一个位置的最大值。
以例题为例如下图所示:
左边是数塔,右边是每次更新的最大值的状态,最终在 f[1][1] 位置即是整个数塔的最大值,输出即可。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=520;
int w[N][N],f[N][N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
cin>>w[i][j];
}
}
for(int i=1;i<=n;i++)f[n][i]=w[n][i];
for(int i=n-1;i;i--)
{
for(int j=1;j<=i;j++)
{
f[i][j]=max(w[i][j]+f[i+1][j],w[i][j]+f[i+1][j+1]);
}
}
cout<<f[1][1]<<endl;
return 0;
}
求路径的数字三角形问题
有一个N层数塔,顶层只有一个结点,每向下一层增加一个结点,最底层有N个结点(下图给出了一个5层数塔)。从顶层出发,每个结点可以选择向左下或者向右下行走,一直走到底层。要求找到一条路径,使得路径上的数值之和最大。例如,下图所示的5层数塔的最大和及其路径为:60=8+15+9+10+18。
输入格式:
输入在N+1进行,首先给出数塔的高度值N。接下来的N行输入数塔各层结点的值,第一行给出顶层结点的一个值,每向下一行增加一个值,每行的值之间用空格间隔。
输出格式:
按照如下格式输出最大值及其路径。
最大值[结点-->结点-->... ... -->结点]
输入样例:
5
8
12 15
4 9 5
8 10 5 13
16 7 18 10 9
输出样例:
60[8-->15-->9-->10-->18]
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=520;
int w[N][N],f[N][N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
cin>>w[i][j];
for(int i=1;i<=n;i++)f[n][i]=w[n][i];
for(int i=n;i;i--)
{
for(int j=1;j<=i;j++)
{
f[i][j]=max(w[i][j]+f[i+1][j],w[i][j]+f[i+1][j+1]);
}
}
cout<<f[1][1]<<"["<<w[1][1]<<"-->";
int j=1;
for(int i=2;i<=n;i++)
{
if(f[i][j]>f[i][j+1])cout<<w[i][j];
else
{
cout<<w[i][j+1];
j++;
}
if(i!=n)cout<<"-->";
}
cout<<"]";
}
解析:
前面的跟上面一样,找路径的思路就是从f[1][1]开始,每次寻找他的最大值f[i][j],顺着路径向下即可。但是要注意 j 是否要加1,如果左边不用加,向右下的话需要加1,找到最大值f[i][j],输出w[i][j]即可。