当前位置: 代码迷 >> 综合 >> [算法] poj 3903 最长上升子序列 dp vs (二分 nlogn)
  详细解决方案

[算法] poj 3903 最长上升子序列 dp vs (二分 nlogn)

热度:39   发布时间:2023-12-14 10:19:28.0
最长上升子序列 - DP  O(n*n)
F[t] 表示从 1 到t这一段中以 t 结尾的最长上升子序列的长度
    F[t] = max{1, F[j] + 1} (j = 1, 2, ..., t - 1, 且A[j] < A[t])
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <stack>
#include <deque>
#include <queue>
#include <bitset>
#include <list>
#include <map>
#include <set>
#include <iterator>
#include <algorithm>
#include <functional>
#include <utility>
#include <sstream>
#include <climits>
#include <cassert>
#define BUG puts("here!!!");using namespace std;
const int N = 100005;
int data[N];
int dp[N];
int main() {int n;while(cin >> n) {for(int i = 1; i <= n; i++) {scanf("%d", &data[i]);}memset(dp, 0, sizeof(dp));for(int i = 1; i <= n; i++)  {dp[i] = 1;}int mmax = 0;if(n > 0) mmax = 1;for(int i = 2; i <= n; i++) {for(int j = 1; j < i; j++) {if(data[j] < data[i]) {dp[i] = max(dp[i], dp[j] + 1);}}mmax = max(mmax, dp[i]);}printf("%d\n", mmax);}return 0;
}
二分 O(nlogn)
    根据F[]的值进行分类。对于F[]的每一个取值k,我们只需要保留满足F[t] = k的所有A[t]中的最小值。设D[k]记录这个值,即D[k] = min{A[t]} (F[t] = k)。
注意到D[]的两个特点:
(1) D[k]的值是在整个计算过程中是单调不上升的。
(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。
利用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断A[t]与D[len]。若A[t] > D[len],则将A[t]接在D[len]后将得到一个更长的上升子序列,len = len + 1, D[len] = A[t];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[t]。令k = j + 1,则有D[j] < A[t] <= D[k],将A[t]接在D[j]后将得到一个更长的上升子序列,同时更新D[k] = A[t]。最后,len即为所要求的最长上升子序列的长度。
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <stack>
#include <deque>
#include <queue>
#include <bitset>
#include <list>
#include <map>
#include <set>
#include <iterator>
#include <algorithm>
#include <functional>
#include <utility>
#include <sstream>
#include <climits>
#include <cassert>
#define BUG puts("here!!!");using namespace std;
const int N = 100005;
int num, D[N];
int main() {int n;while(cin >> n) {D[0] = -1;int top = 0;for(int i = 1; i <= n; i++) {scanf("%d", &num);if(num > D[top]) {top++;D[top] = num;}else {int low = 1, high = top;while(low <= high) {int mid = (low+high) >> 1;if(num > D[mid]) {low = mid + 1;}else high = mid - 1;}D[low] = num;}}printf("%d\n", top);}return 0;
}
  相关解决方案