欢迎访问我的pat顶级题解目录哦 https://blog.csdn.net/richenyunqi/article/details/86751676
题目描述
算法设计
这是一道考察最长上升子序列问题(LIS) 的题目。定义数组A[n+1]
存储整个序列;定义数组dpLeft[n+1]
,其中dpLeft[i]
表示序列A[1]~A[i]
中以A[i]
结尾的不包含A[i]
的最长上升子序列的长度;定义数组dpRight[n+1]
,其中dpRight[i]
表示序列A[n]~A[i]
中以A[i]
结尾的不包含A[i]
的最长上升子序列的长度。
那么对于A[i]
,存在以A[i]
为中心的peak shape
的条件为dpleft[i]>0&&dpRight[i]>0
,整个peak shape
的长度为dpleft[ans]+dpRight[ans]+1
。
关于dpLeft
和dpRight
的求解大致相同,以dpLeft
为例,其状态转移方程为
d
p
L
e
f
t
[
i
]
=
m
a
x
{
d
p
L
e
f
t
[
i
]
,
d
p
L
e
f
t
[
j
]
+
1
∣
j
<
i
,
A
[
j
]
<
A
[
i
]
}
dpLeft[i]=max\{dpLeft[i],dpLeft[j]+1|j<i,A[j]<A[i]\}
dpLeft[i]=max{dpLeft[i],dpLeft[j]+1∣j<i,A[j]<A[i]}
具体实现可见代码。
C++代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,ans=0;//ans存储最终结果peak number的下标
scanf("%d",&n);
int A[n+1],dpleft[n+1]={0},dpRight[n+1]={0};//将dpleft、dpRight均初始化为0
for(int i=1;i<=n;++i)
scanf("%d",&A[i]);
for(int i=1;i<=n;++i)//求解dpLeft
for(int j=1;j<i;++j)
if(A[i]>A[j])
dpleft[i]=max(dpleft[i],dpleft[j]+1);
for(int i=n;i>=1;--i)//求解dpRight
for(int j=n;j>i;--j)
if(A[i]>A[j])
dpRight[i]=max(dpRight[i],dpRight[j]+1);
for(int i=1;i<=n;++i)//求解ans
if(dpleft[i]>0&&dpRight[i]>0&&(dpleft[i]+dpRight[i]>dpleft[ans]+dpRight[ans]||
(dpleft[i]+dpRight[i]==dpleft[ans]+dpRight[ans]
&&abs(dpleft[i]-dpRight[i])<abs(dpleft[ans]-dpRight[ans]))))
ans=i;
if(ans==0)
puts("No peak shape");
else
printf("%d %d %d",dpleft[ans]+dpRight[ans]+1,ans,A[ans]);
return 0;
}