HDU 1051 Wooden Sticks(LIS)

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


你可能感兴趣的:(HDU 1051 Wooden Sticks(LIS))