https://vjudge.net/problem/POJ-2533#author=karl_sc
poj天天炸 放个VJ页面吧(逃
很经典的LIS( longest increasing subsequence )
说实话今天学习真的没有状态 可能是有点疲惫了?。。。
刚开始深入的学dp 那这个经典问题好好的谈一谈
我们知道dp的经典思维就是看上一个的状态 因此 最长上升子序列也就是n的最长上升子序列也就是n-1的最长上升子序列 我也不知道我说了一句什么话 还是列公式吧
lis[i]=max(lis[j])+1(arr[j]<arr[i]) 就是说 每找到一个数 就遍历所有的数字 找到比他小且lis最大的那个数字 然后 就是那个数的lis+1
举个例子:
1 7 3 5 9 4 8
lis[1]=1;
lis[2]=1+1=2;
lis[3]=1;
lis[4]=lis[1]+1=2;
lis[5]=lis[4]+1=3;
lis[6]=lis[3]+1=2;
lis[7]=lis[3]+1=2;
lis[8]=lis[5]+1=4;
lis[9]=lis[8]+1=5;
代码很简单 但是今天很迷的状态还是写错了不少地方 好菜
分析下时间复杂度 每一个数都要便利前面所有的数字 O(n^2)无疑了
#include<algorithm> #include<iostream> #include<vector> #include<cstdio> #include<cstring> #include<cmath> #include<string> #include<ctime> #include<map> #include<stack> #include<set> #include<cstring> #include<sstream> using namespace std; typedef long long ll; const int maxn = 1005; int lis[maxn]; int arr[maxn]; int main() { ios::sync_with_stdio(0); cin.tie(0); int n; cin >> n; for (int i = 0; i < n; i++) { cin >> arr[i]; } lis[0] = 1; int maxn = 0; for (int i = 1; i < n; i++) { maxn = 0; for (int j = 0; j < i; j++) { if (arr[i] > arr[j]) { maxn = max(maxn, lis[j]); } } lis[i] = maxn+1; } int ans = 0; for (int i = 0; i < n; i++) { ans = max(ans, lis[i]); } cout << ans << endl; return 0; }
好 那么我们知道 n2的复杂度是有点丑的
我们可以把他优化为nlogn的复杂度
来 讲讲我们下一种想法
还是那个例子 1 7 3 5 9 4 8
我们搞一个数组B
扫一遍数组
1 入 B:1
7 入 B: 1 7
3 入 B: 1 3
5 入 B: 1 3 5
9 入 B: 1 3 5 9
4 入 B: 1 3 4
8 入 B: 1 3 4 8
你看 这样B 是不是就是我们要的数组啦 但是有个疑问 这不还是扫了两边吗
等等 这个时候 我们的二分查找就来了 查找的时候用二分 n变logn
妈的心态炸了 写了这么久的Lower_bound 都是wa 找了个大佬的直接贴一下
来自:https://blog.csdn.net/aqa2037299560/article/details/82873340
#include<algorithm> #include<iostream> #include<vector> #include<cstdio> #include<cstring> #include<cmath> #include<string> #include<ctime> #include<map> #include<stack> #include<set> #include<cstring> #include<sstream> using namespace std; typedef long long ll; int i, j, n, s, t, a[100001]; int main() { cin >> n; a[0] = -1000000; for (i = 0; i < n; i++) { cin >> t; if (t > a[s]) a[++s] = t; else { int l = 1, h = s, m; while (l <= h) { m = (l + h) / 2; if (t > a[m]) l = m + 1; else h = m - 1; } a[l] = t; } } cout << s << endl; }
还有一种树状数组的做法 这里不谈了
https://blog.csdn.net/George__Yu/article/details/75896330
Comments | NOTHING