一、数字三角形
问题描述:给出一个每行递增的数字三角形,只能从当前数字走到下一行相邻数字,求从数字三角形的顶端到底部的路径最长为多少。
问题分析:每个数字所处的路径有两条,拿图中第四行的数字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算法基础