【算法基础21】线性DP问题上(数字三角形、最长上升子序列)

一、数字三角形

        问题描述:给出一个每行递增的数字三角形,只能从当前数字走到下一行相邻数字,求从数字三角形的顶端到底部的路径最长为多少。

        问题分析:每个数字所处的路径有两条,拿图中第四行的数字7举例,一条是来自左上方数字8,一条是来自右上方数字1,则到数字7为止的最长路径应该是两条来路中的最长路径再加上7。将一个数字的最长路径求法推广到整个数字三角形上,可以得出递推公式f[ i ][ j ] = max(f[ i-1 ][ j-1 ] , f[ i-1 ][ j ])+a[ i ][ j ]

                ​​​​​​​        ​​​​​​​        

 

        代码:

#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010,INF=1e9;
int f[N][N],a[N][N];

int main(){
	int n;
	cin>>n;
	
	for(int i=1;i<=n;i++){//存入数字三角形
		for(int j=1;j<=i;j++){
			cin>>a[i][j];
		}
	}
	
	for(int i=1;i<=n;i++){//初始化
		for(int j=1;j<=i+1;j++){//三角形最右边上的数字没有来自右上角的路径,多初始化一个
			f[i][j]=-INF;
		}
	}
	f[1][1]=a[1][1];
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			f[i][j]=max(f[i-1][j-1],f[i-1][j])+a[i][j];//代入递推公式
		}
	}
	
	int res=-INF;
	for(int i=1;i<=n;i++) res=max(res,f[n][i]);//求底部路径最大值
	cout<<res<<endl;
	
	return 0;
}

二、最长上升子序列

        问题描述:给出一个由不同数字组成的序列,求递增子序列最长为多少。

        问题分析:以第 i 个数结尾的最长上升子序列的长度,一定是以 1 到 i-1 结尾的 i-1 个子序列中最长的序列长度再加 1 。

        代码:

        只记录序列长度:

#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;
int a[N],f[N];

int main(){
	int n;
	cin>>n;
	
	for(int i=1;i<=n;i++) cin>>a[i];//存入给定序列
	
	for(int j=1;j<=n;j++){
		f[j]=1;//最坏情况为只有它自己,长度为1
		for(int i=1;i<j;i++){//遍历前 j-1 个序列
			if(a[i]<a[j]){//满足上升序列要求
				f[j]=max(f[j],f[i]+1);
			}
		}
	}
	
	int res=0;
	for(int i=1;i<=n;i++) res=max(res,f[i]);
	cout<<res;
	
	return 0;
}

        记录序列具体值:

#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;
int a[N],f[N],g[N];

int main(){
	int n;
	cin>>n;
	
	for(int i=1;i<=n;i++) cin>>a[i];
	
	for(int j=1;j<=n;j++){
		f[j]=1;
		for(int i=1;i<j;i++){
			if(a[i]<a[j]){
				if(f[j]<=f[i]){//替换max函数
					f[j]=f[i]+1;
					g[j]=i;//g[]存储前一位的值
				}
			}
		}
	}
	
	int k=1;
	for(int i=1;i<=n;i++){//找序列长度最长的下标
		if(f[i]>f[k]) k=i;
	}		
	cout<<f[k]<<endl;
	
	for(int i=0,len=f[k];i<len;i++){//逆序输出最长序列,如需正序再利用栈
		cout<<a[k]<<' ';
		k=g[k];
	}
	
	return 0;
}

参考资料:ACWing算法基础

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值