<—点个赞吧QwQ
宣传一下算法基础课整理
给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数 N 。
第二行包含 N 个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000 ,
−109≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
思路
闫氏 DP 分析法:
状态表示: fi
- fi 表示从第一个数开始算,以第 i 个数结尾的最长上升子序列
状态计算:
- 如果我们选第 1 个数,且第 1 个数小于第 i 个数,那么对应的就是 f1
- 如果我们选第 2 个数,且第 2 个数小于第 i 个数,那么对应的就是 f2
- 如果我们选第 j 个数,且第 j 个数小于第 i 个数,那么对应的就是 fj
- 所以状态转移方程就是 fi=max
初始化:
- 因为每一个数以自己结尾的最长上升子序列的长度为 1 ,所以初始 \underset{1\le i \le n}{f_i}=1
答案:
- 根据定义,由于每一个数都有可能成为最长上升子序列的最后一个数,所以答案就是 \underset{1\le i\le n}\max \lbrace f_i \rbrace
代码
#include <iostream>
using namespace std;
const int N = 1010;
int n;
int a[N];
int f[N];
int main () {
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
int ans = 0;
for (int i = 1;i <= n;i++) {
f[i] = 1;
for (int j = 1;j < i;j++) {
if (a[j] < a[i]) f[i] = max (f[i],f[j] + 1);
}
ans = max (ans,f[i]);
}
cout << ans << endl;
return 0;
}
这道题用递归写还会快一点,而且也不会爆栈
orz _ {orz}
{orz ^ {orz}}
牛逼牛逼!
为什么我把循环里的f[i] = 1去掉,在循环外面memset(f, 1, sizeof f)就不对了呢?
建议学一下memset的原理
自己查吧,我的语文太差了
memset建议只赋0或-1值,赋其他值容易出错
还有0x3f,0x7f,0xcf都常用
memset
是逐字节填充,int
是 4 个字节,每个字节有 8 位,所以如果直接memset(f, 1, sizeof f)
会使 f 数组中的每个数都变成二进制下的00000001 00000001 00000001 00000001
,这显然会出错