题目链接:Click here~~
题意:
很经典的问题,记得是黑书上的一道思考题。
模型转换完之后意思大概就是,给一个二元组<a,b>,给一个偏序关系a1<a2 && b1<b2,找若干单调序列使得序列个数最小。
解题思路:
首先,有个贪心的解法,不过还不会证明正确性,复杂度O(n^2)。
#include <queue> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 5e3+5; struct T { int a,b; bool operator < (const T& S)const { return a < S.a || a == S.a && b < S.b; } }; int main() { int z,n; scanf("%d",&z); while(z--) { deque<T> A; scanf("%d",&n); for(int i=0;i<n;i++) { T tmp; scanf("%d%d",&tmp.a,&tmp.b); A.push_back(tmp); } sort(A.begin(),A.end()); int ans = 0; while(!A.empty()) { int maxb = A.front().b; A.pop_front(); for(int i=0;i<(int)A.size();i++) { if(maxb <= A[i].b) { maxb = A[i].b; A.erase(A.begin()+i); --i; } } ++ans; } printf("%d\n",ans); } return 0; }另外,这题可以用 LIS 做,复杂度为O(n*logn):
首先,将元素按照 a 降序排列,然后,再以 b 为关键字求元素的 LIS ,LIS 的长度就是问题的解。
为什么呢?一个事实是,求得的 LIS 序列中,a递减、b递增,也就是它们两两不能放在一起。
所以,我们至少需要这么多序列,来放所有的元素。
而剩下的元素,都至少可以找到 LIS 中的一个元素,来放入,故 LIS 的长度就是问题的解。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 5e3+5; struct TT { int a,b; bool operator<(const TT& T)const { return a>T.a || a==T.a && b>T.b; } }A[N]; int dp[N]; int Bsearch(int *a,int l,int r,int x) { while(l < r) { int mid = l+r >> 1; if(a[mid] < x) l = mid+1; else r = mid; } return r; } int LIS(int n) { dp[1] = A[0].b; int top = 1; for(int i=1;i<n;i++) { if(dp[top] < A[i].b) dp[++top] = A[i].b; else dp[Bsearch(dp,1,top,A[i].b)] = A[i].b; } return top; } int main() { int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&A[i].a,&A[i].b); sort(A,A+n); printf("%d\n",LIS(n)); } return 0; }
Ps:此题为非严格递增。二分可以调用 upper_bound。
若为严格递增,排序和判断大小处还需要修改,用 lower_bound。http://acm.hdu.edu.cn/showproblem.php?pid=1677
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 2e4+5; struct TT { int a,b; bool operator<(const TT& T)const { return a>T.a || a==T.a && b<T.b; } }A[N]; int dp[N]; int Bsearch(int *a,int l,int r,int x) { while(l < r) { int mid = l+r >> 1; if(a[mid] <= x) l = mid+1; else r = mid; } return r; } int LIS(int n) { dp[1] = A[0].b; int top = 1; for(int i=1;i<n;i++) { if(dp[top] <= A[i].b) dp[++top] = A[i].b; else dp[Bsearch(dp,1,top,A[i].b)] = A[i].b; } return top; } int main() { int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&A[i].a,&A[i].b); sort(A,A+n); printf("%d\n",LIS(n)); } return 0; }