题目链接: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;
}