Cracking the coding interview--Q9.7

January 22, 2013
作者:Hawstein
出处:http://hawstein.com/posts/9.7.html
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。

题目

原文:

A circus is designing a tower routine consisting of people standing atop one another’s shoulders. For practical and aesthetic reasons, each person must be both shorter and lighter than the person below him or her. Given the heights and weights of each person in the circus, write a method to compute the largest possible number of people in such a tower.

EXAMPLE:

Input (ht, wt): (65, 100) (70, 150) (56, 90) (75, 190) (60, 95) (68, 110)

Output: The longest tower is length 6 and includes from top to bottom: (56, 90) (60,95) (65,100) (68,110) (70,150) (75,190)

译文:

马戏团设计了这样一个节目:叠罗汉。一群人往上叠,每个人都踩在另一个人的肩膀上。 要求上面的人要比下面的人矮而且比下面的人轻。给出每个人的身高和体重, 写一个函数计算叠罗汉节目中最多可以叠多少人?

例子:

输入(身高 体重):(65, 100) (70, 150) (56, 90) (75, 190) (60, 95) (68, 110)

输出:最多可叠人数:6 (从上到下是:(56, 90) (60,95) (65,100) (68,110) (70,150) (75,190))

解答

给定了(身高 体重)序列,要求我们排序。不过由于要排序的对象是一个结构, 我们可以先按其中的一个指标进行排序,比如说身高。身高排好序后, 身高这个指标就都是满足叠罗汉的要求了,剩下的就看体重。 我们就只要在体重那个维度找到最长的递增子序列就可以了。

我们先定义一个结构体:

const int maxn = 100;
struct person{
    int h, w;
};
person p[maxn];

然后为了使STL中的sort函数能对这个结构体先按身高排序,当身高相等时按体重排序, 我们还需要写一个对比函数作为sort的参数:

bool cmp(person p1, person p2){
    if(p1.h == p2.h) return p1.w < p2.w;
    else return p1.h < p2.h;
}

这样一来,当我们调用sort函数,就能达到先对身高排序,若身高相等时对体重排序的要求。

sort(p, p+n, cmp);

排好序后,只需要求体重序列的最长递增子序列(LIS)即可。关于求LIS,可以参考文章: 动态规划:从新手到专家

int lis(person p[], int n){
    int k = 1;
    d[0] = p[0].w;
    for(int i=1; i<n; ++i){
        if(p[i].w >= d[k-1]) d[k++] = p[i].w;
        else{
            int j;
            for(j=k-1; j>=0 && d[j]>p[i].w; --j);//用二分可将复杂度降到O(nlogn)
            d[j+1] = p[i].w;
        }
    }
    return k;
}

完整代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 100;
struct person{
    int h, w;
};
person p[maxn];
int d[maxn];

bool cmp(person p1, person p2){
    if(p1.h == p2.h) return p1.w < p2.w;
    else return p1.h < p2.h;
}
int lis(person p[], int n){
    int k = 1;
    d[0] = p[0].w;
    for(int i=1; i<n; ++i){
        if(p[i].w >= d[k-1]) d[k++] = p[i].w;
        else{
            int j;
            for(j=k-1; j>=0 && d[j]>p[i].w; --j);//用二分可将复杂度降到O(nlogn)
            d[j+1] = p[i].w;
        }
    }
    return k;
}
int main(){
    freopen("9.7.in", "r", stdin);
    int n;
    cin>>n;
    for(int i=0; i<n; ++i)
        cin>>p[i].h>>p[i].w;
    sort(p, p+n, cmp);
    cout<<lis(p, n)<<endl;
    fclose(stdin);
    return 0;
}

全书题解目录:

Cracking the coding interview–问题与解答

全书的C++代码托管在Github上:

https://github.com/Hawstein/cracking-the-coding-interview