poj-1631-Bridging signals-最长上升序列(LIS)
2017-08-14 10:55
423 查看
额(⊙o⊙)… 先放题目链接
题目传送门:https://vjudge.net/problem/POJ-1631
题目就是求最长上升序列(自己想想吧!)
lis是啥——>一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
测试数据(题目上给的太扯犊子了)
这样多好看,真是的!^_^
首先
我们来看一种方法:大致运用dp来做的
直接上代码,学过一点点dp的估计都看的懂!不懂就留言吧!
估计会有人直接去提交,我可没说是ac的代码,这是tl的代码,其实一看,就知道超时 一个for和两个for嵌套,肯定的
(・ω・`ll),复杂度为n^2
换方法吧!先上代码^_^
其中对第一个代码,有个巨大的优化,这个复杂度为n*logn
首先
len = 1,dp[1] = a[1],然后对a[i]:若a[i]>dp[len],那么len++,dp[len] = a[i];
否则
我们要从d[1]到dp[len-1]中找到一个j,满足dp[j-1]<a[i]<d[j]
则
根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 dp[j] = a[i];
最终
答案就是len
利用dp的单调性,在查找j的时候可以二分查找,从而时间复杂度为n*logn
再看一个用stl写的
函数具体,看大牛的博客吧!
http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html
好
了
这
就
结
束
了
吗
!
好吧!没有,最近在学习树状数组,忽然我……………………………………
在网上看到了,一个用来树状数组写的,还不错就打了一遍!
不解释,想看就看,不看也无关!
最后,推荐一个博客吧!讲了三种解决方法(写的很好,但是感觉没必要)
http://blog.csdn.net/george__yu/article/details/75896330#reply
题目传送门:https://vjudge.net/problem/POJ-1631
题目就是求最长上升序列(自己想想吧!)
lis是啥——>一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
测试数据(题目上给的太扯犊子了)
Sample Input
4 6 4 2 6 3 1 5 10 2 3 4 5 6 7 8 9 10 1 8 8 7 6 5 4 3 2 1 9 5 8 9 2 3 1 7 4 6
Sample Output
3
9
1
4
这样多好看,真是的!^_^
首先
我们来看一种方法:大致运用dp来做的
直接上代码,学过一点点dp的估计都看的懂!不懂就留言吧!
#include <algorithm> #include <iostream> #include <cstring> #includ c32c e <cstdlib> #include <cstdio> #include <cmath> #include <queue> #include <set> #include <map> #define N 40005 using namespace std; int a ; int dp ; int main() { int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); int mmax = -1; for(int i = 1; i <= n; i++) { dp[i] = 1; for(int j = 1; j <= i; j++) { if(a[i] > a[j] && dp[i] < dp[j] + 1) dp[i] = dp[j] + 1; } mmax = max(mmax, dp[i]); } printf("%d\n", mmax); } return 0; }
估计会有人直接去提交,我可没说是ac的代码,这是tl的代码,其实一看,就知道超时 一个for和两个for嵌套,肯定的
(・ω・`ll),复杂度为n^2
换方法吧!先上代码^_^
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <queue> #include <set> #include <map> #define N 40005 using namespace std; int a ; int dp ; int main() { int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); int len = 1; dp[1] = a[1]; for(int i = 2; i <= n; i++) { if(a[i] > dp[len]) { len++; dp[len] = a[i]; continue; } int l = 1, r = len; while(l <= r) { int mid = (l + r) / 2; if(dp[mid] > a[i]) r = mid - 1; else l = mid + 1; } dp[l] = a[i]; } printf("%d\n", len); } return 0; }
其中对第一个代码,有个巨大的优化,这个复杂度为n*logn
首先
len = 1,dp[1] = a[1],然后对a[i]:若a[i]>dp[len],那么len++,dp[len] = a[i];
否则
我们要从d[1]到dp[len-1]中找到一个j,满足dp[j-1]<a[i]<d[j]
则
根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 dp[j] = a[i];
最终
答案就是len
利用dp的单调性,在查找j的时候可以二分查找,从而时间复杂度为n*logn
再看一个用stl写的
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; typedef long long LL; const int maxn=500009; const int INF=0x3f3f3f3f; int n; int a[maxn]; int dp[maxn]; int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); dp[0]=0; int len=0; for(int i=1; i<=n; i++) { if(a[i]>dp[len]) { dp[++len]=a[i]; continue; } int t=upper_bound(dp, dp+len, a[i])-s; dp[t]=a[i]; } printf("%d\n", len); } return 0; }
函数具体,看大牛的博客吧!
http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html
好
了
这
就
结
束
了
吗
!
好吧!没有,最近在学习树状数组,忽然我……………………………………
在网上看到了,一个用来树状数组写的,还不错就打了一遍!
不解释,想看就看,不看也无关!
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <queue> #include <set> #include <map> #define N 40005 #define MAX 0x3f3f3f3f using namespace std; struct point { int num, x; }a ; int dp , n; bool comp(point a, point b) { if(a.num == b.num) return a.x < b.x; return a.num < b.num; } int lowbit(int x) { return x & (-x); } int find(int x) { int ret = -MAX; while(x) { ret = max(ret, dp[x]); x -= lowbit(x); } return ret; } void change(int x ,int y) { while(x <= n) { dp[x] = max(dp[x], y); x += lowbit(x); } } int main() { int T; scanf("%d", &T); while(T--) { memset(dp, 0, sizeof(dp)); scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i].num); a[i].x = i; } sort(a + 1, a + n + 1, comp); int ans = 0; for(int i = 1; i <= n; i++) { int mmax = find(a[i].x); change(a[i].x, ++mmax); ans = max(ans, mmax); } printf("%d\n", ans); } return 0; }
最后,推荐一个博客吧!讲了三种解决方法(写的很好,但是感觉没必要)
http://blog.csdn.net/george__yu/article/details/75896330#reply
相关文章推荐
- 最长上升子序列(LIS)POJ 1631 Bridging Signals
- POJ 1631(最长上升子序列 nlogn).
- 【最长上升子序列】北大 POJ 1631 Bridging signals
- poj 2533 poj3903 poj1836 最长上升子序列 LIS
- POJ 1631 Bridging signals(最长上升子序列 n*logn && POJ 3903)
- poj 1631 Bridging signals【最长上升子序列】
- poj1631 dp 最长上升子序列LIS
- Poj 1631 n*logn 的最长上升子序列(LIS)算法
- poj 1631 / nlogn 算法 求 最长上升子序列长度
- POJ 1631 HDU 1950(最长上升子序列问题)
- POJ 1631 Bridging signals(最长上升序列)
- POJ 1631 Bridging signals(LIS:最长上升子序列)
- POJ 1631 Bridging signals(最长上升子序列 nlgn做法)
- POJ 1631 Bridging signals (LIS:最长上升子序列)
- poj 1631 Bridging signals LIS 最长非递减子序列
- poj 1631 Bridging signals (LIS 最长递增子序列 DP-二分)
- POJ 1631 : Bridging signals - 最长上升子序列 O(nlog n)
- poj 1631 最长上升子序列 nlogn
- [算法] poj 3903 最长上升子序列 dp vs (二分 nlogn)
- 最长上升子序列(LIS)