Nested Dolls (单调递增子序列 + 二分)

Description

Dilworth is the world’s most prominent collector of Russian nested dolls: he literally has thousands of them! You know, the wooden hollow dolls of different sizes of which the smallest doll is contained in the second smallest, and
this doll is in turn contained in the next one and so forth. One day he wonders if there is another way of nesting them so he will end up with fewer nested dolls? After all, that would make his collection even more magnificent! He unpacks each nested doll
and measures the width and height of each contained doll. A doll with width w1 and height h1 will fit in another doll of width w2 and height h2 if and only if w1 < w2 and h1 < h2. Can you help him calculate the smallest number of nested dolls possible to assemble
from his massive list of measurements?

Input

On the first line of input is a single positive integer 1 <= t <= 20 specifying the number of test cases to follow. Each test case begins with a positive integer 1 <= m <= 20000 on a line of itself telling the number of dolls in the
test case. Next follow 2m positive integers w1, h1,w2, h2, . . . ,wm, hm, where wi is the width and hi is the height of doll number i. 1 <= wi, hi <= 10000 for all i.

Output

For each test case there should be one line of output containing the minimum number of nested dolls possible.

Sample Input

4
3
20 30 40 50 30 40
4
20 30 10 10 30 20 40 50
3
10 30 20 20 30 10
4
10 10 20 30 40 50 39 51 

Sample Output

1
2
3
2 

题目大意:

就是有一堆的长和宽知道的玩偶,小的玩偶可以嵌套在大的里面,只有当长和宽都比它要嵌套在里面的小的时候才可以(长宽不能互换)问多有嵌套完毕后,还有多有个玩偶(最少的)。

解题思路:

要求出最多的能嵌套的个数,如果用贪心思想,势必会TLE,必然要寻求别的方法,因为长或宽相同的不能嵌套,那么如果对长按照从大到小的顺序排列,对于长相等的按照从小到大的顺序排列,那么对宽求单调递增子序列即可。不管什么情况,都可以求得最优解。

一个重要的是要用二分求解最长公共子序列获取最优解,主要是为了优化时间。

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <cmath>
#include <string>
#define INF 0x3f3f3f3f
using namespace std;
struct Data
{
    int w, h;
}s[20010];

bool cmp(Data A, Data B)
{
    if(A.w != B.w)
        return A.w > B.w;
    else
        return A.h < B.h;
}

int main()
{
    int t, i, j, sum, n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i = 1; i <= n; i++)
        {
            scanf("%d%d",&s[i].w,&s[i].h);
        }
        sort(s + 1, s + n + 1, cmp); // 对长从大到小排序,宽从小到大排序
        int b[20010],dp[20010];
        memset(b, 0, sizeof(b));
        memset(dp, 0, sizeof(dp));
        sum = -1;
        b[0] = -1;
        dp[0] = 0;
        int top;
        for(i = 1, top = 0; i <= n; i++)//利用二分法对宽求最长公共子序列
        {
            if(s[i].h >= b[top])
            {
                b[++top] = s[i].h;//b数组记录最长公共子序列
                dp[i] = top;//记录当前点的最长公共子序列的元素个数

            }
            else
            {
                 int l = 1, r = top;
                 while(l <= r)//二分
                 {
                     int mid = (l + r) / 2;
                     if(s[i].h >= b[mid])
                     {
                         l = mid + 1;
                     }
                     else
                        r = mid - 1;
                 }
                 b[l] = s[i].h;
                 dp[i] = l;
            }
            if(dp[i] > sum)
               sum  = dp[i];
        }
        printf("%d\n",sum);
    }
    return 0;
}
时间: 2024-10-10 20:25:50

Nested Dolls (单调递增子序列 + 二分)的相关文章

nyoj 214——单调递增子序列(二)——————【二分搜索加dp】

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7)每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=10

最长单调递增子序列 POJ 3903 Stock Exchange .

题目传送门 : -------->点这里点这里<---------- 题目大意: 给出一串正整数,个数为N个.1<=N<=100000.求最长单调递增子序列长度. 样例输入: 6 5 2 1 4 5 3 3 1 1 1 4 4 3 2 1 样例输出: 3 1 1 =================================================================== 最长单调递增子序列问题的DP朴素算法复杂度为 O(n^2); 然而题目中的 N 最大有

单调递增子序列(二)(南阳oj214)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

最长单调递增子序列的三种解法

问题描述: 找出由n个数组成的序列的最长单调递增子序列 解法一:转化成LCS问题求解,时间复杂度为O(n*n). 思路:原序列为A,把A按升序排序得到序列B,求出A,B序列的最长公共子序列,即为A的最长单调递增子序列. #include<iostream> #include<algorithm> #include<string> #include<cstdio> using namespace std; //转化成LCS问题,时间复杂度O(n*n) int

nyist oj 214 单调递增子序列(二) (动态规划经典)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

单调递增子序列(二)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

nyoj 214 单调递增子序列(二) 【另类dp】

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

最长单调递增子序列——动态规划

题目描述: 给定一个序列X[0···n],找出它的最长的单调递增子序列(Longest Increasing Subsequence) 解题思路: 使用动态规划方法. 对于i= 1, 2, --,n,考虑以xi作为最后项的最长递增子序列的长度C[i]. 如果在xi项前面存在xj < xi , 那么 C[i] = max{C[j]} +1:否则,C[i] = 1. 因此, C[i] = max{C[j]} + 1, 存在j,1<=j<i, xj<xi C[i] = 1, 所有j,1&

hdoj 5087 Revenge of LIS II 【第二长单调递增子序列】

题目:hdoj 5087 Revenge of LIS II 题意:很简单,给你一个序列,让你求第二长单调递增子序列. 分析:其实很简单,不知道比赛的时候为什么那么多了判掉了. 我们用O(n^2)的时间求单调递增子序列的时候,里面在加一层循环维护sum数组,表示前面有几个可以转移当当前,求前面sum的和保存到当前. 最后求最后一个sum[n-1]是否为1就ok,为1的话在最长的基础上减一,否则就是最长的. AC代码: #include <iostream> #include <algor