按道理来说,线性dp的问题基本都能用暴力解出来,dfs+记录,我们基本能解决所有线性dp问题,但是,博主作为一个备考蓝桥杯的人,暴力骗分一定要会,同时也要会正确的做题方法;
所以这里也呼吁和我一样的菜鸟新手学会多种解法,至少对于这种不是ACM赛制的题,要学会:不会也要骗一点分;
废话多说了,让我们来看题,直接分析,根据闫氏动态规划分析,我们这里先分析状态表示,因为要我们查找权重最大的路径,而且输入也给的很清晰,直接开二维数组存储,i表示第i行,j表示j列,这样可以存储权重和位置;
我们用arr数组存储权重,用dist存储到达当前点的最大权重路径;
那么分析完成,如何表示状态转移呢?
看:
因为这道题给的很巧妙,所以我们的存储也有技巧,这样的话,因为我们的dist数组存储的是到这个点的时候,最大的权重路径,而这个点可以被下面的两个使用。
具体的求法:
某个点的最大权重路径由这个点上面的点和上面左边的点决定,我们只需要取其中的最大值即可
具体代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510,INF=1e9;
int arr[N][N];
int dist[N][N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
cin>>arr[i][j];//正常存储
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
dist[i][j]=-INF;//我们需要考虑负权边,如果出现负权边,就会出现有一些点
//遍历到了0,而没有另一个点大,从而使答案错误
dist[1][1]=arr[1][1];//加不加都可以,不加的话下面从i=1遍历
for(int i=2;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
dist[i][j]=max(dist[i-1][j]+arr[i][j],dist[i-1][j-1]+arr[i][j]);//取大值存储
// cout<<dist[i][j]<<' ';
}
// cout<<endl;
}
int max=-INF;
for(int i=1;i<=n;i++)
if(dist[n][i]>max)
max=dist[n][i];//要的是到达底边的所有路中的最大值,所以需要遍历一遍
cout<<max;//输出
}
负权边情况:
如果不赋值为负无穷值,那么根据我们的分析,我们的dist数组应该是这样:
实际上,这是错误的,因为i=2,j=1时,我们只有一个上点,但是分析的时候会把-6左边的零算进去,结果当然是0>-6,所以会出现路径为-6的情况,如果赋值为无穷大就不会出现这种情况。
至此,完结撒花。