AcWing 1014. 登山
原题链接
简单
作者:
YMYS
,
2024-12-18 18:46:48
,
所有人可见
,
阅读 7
/*
* @Author: YMYS
* @Date: 2024-12-17 08:44:40
* @LastEditTime: 2024-12-18 21:15:09
* @FilePath: \VScode-C&C++-Coding\Acwing\算法提高课\1.动态规划\2.最长上升子序列模型\2.登山.cpp
* @URL:https://www.acwing.com/problem/content/1016/
* @Description: 1014. 登山
*
* 题意:
* 1、每次所浏览景点的编号都要大于前一个浏览景点的编号。
* 意思就是:只能单向走,可以先上升后下降,
*
* 这里的话我们可以分两次讨论,
* 一次为:求每个点i为起点的上升序列
* 另一次为:求每个点i为起点的下降序列
* 最后将两次的max相加即可
*
* 2、一旦开始下山,就不再向上走了。
* 意思就是:最优解一定是先上升后下降
*
* 3、尽可能多的浏览景点
* 意思就是:取最长
*
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n;
int w[N],f[N],g[N];
// int T;
// void solve(){
// }
int main()
{
#ifdef ABC
freopen("D:\\daily_Coding\\VScode-C&C++-Coding\\in.in", "r", stdin);
freopen("D:\\daily_Coding\\VScode-C&C++-Coding\\out.out", "w", stdout);
#endif
// cin>>T;
// while(T--){
// solve();
// }
cin>>n;
for(int i=1;i<=n;i++) cin>>w[i];
//求每个点w[i],正着走上升时的max_f[i]
for(int i=1;i<=n;i++){
f[i] = 1;
for(int j=1;j<i;j++){//1~i-1
if(w[i]>w[j]){
f[i] = max(f[i], f[j]+1);
}
}
}
//求每个点w[i],倒着走上升的max_g[i]。
//这里一定要倒着走,因为我们要找的是w[i]右边的比w[i]小的数。
//不可以【正着走下降】去遍历,因为那样找的是w[i]左边比w[i]大的数
for(int i=n;i>=1;i--){
g[i] = 1;
for(int j=n;j>i;j--){//1~i-1
if(w[i]>w[j]){
g[i] = max(g[i], g[j]+1);
}
}
}
//下面这个循环替换成上面第27行那个循环后,就不能AC了。
//为什么呢?因为下面这层循环找的是w[i]的左边比w[i]大的。但是我们在该题中,想找的是在w[i]的右边比w[i]小的
//因此我们想在哪边找,就一定要按着哪个方向去遍历。
// for(int i=1;i<=n;i++){
// g[i] = 1;
// for(int j=1;j<i;j++){//1~i-1
// if(w[i]<w[j]){
// g[i] = max(g[i], g[j]+1);
// }
// }
// }
//为什么要减一呢,因为山峰那个点对于两条线【f[]、g[]】是重合的
int res = 1;
for(int i=1;i<=n;i++){
res = max(res, f[i]+g[i]-1);
}
cout<<res<<endl;
return 0;
}