DP经典应用(四)二维最长上升子序列问题——矩形嵌套问题

来源:互联网 发布:查看一个ip绑定的域名 编辑:程序博客网 时间:2024/05/22 22:42

矩形嵌套问题

问题描述:输入多个矩形的长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a < c,b < d或者b < c,a < d,任务是选出尽可能多的矩形排成一行,使得除了最后一个之外,每一个矩形都可以嵌套在下一个矩形内求出最多嵌套矩形的个数。

注意加粗的一段话,就要求我们必须先排序

样例输入:

1101 22 45 86 107 93 15 812 109 72 2

样例输出:

5

分析:

这个问题是不是和最长递增子序列的问题十分类似。
只不过这个子序列的数不只是一个数,而是长和宽罢了。
所以只要会转换一下就十分简单了。

依然按照分析动态规划的3个步骤:
按照3个步骤:

  • 1.刻画最优解结构特征:
    定义dp[i]为以第i个矩形pi为末尾的整个矩形序列中能够被嵌套的最多数目

  • 2.递归地定义最优解的值:
    以第i个矩形pi为末尾元素的序列是:
    1.只包含第i个矩形pi的序列
    2.如果满足j < i 并且 pj.l < pi.l && pj.w < pi.w这个条件的以pj为末尾的序列末尾再加上pi后得到的新序列。
    这两者之一。
    所以得到此递推式:
    dp[i] = max(dp[i],dp[j]+1) (j < i 且 pj.l < pi.l && pj.w < pi.w)

  • 3.计算最优解的值(递推)
    代码如下:

#include<cstdio>#include<algorithm>using namespace std;const int maxn = 100;struct P{    int l,w;}p[maxn];int max(int a,int b){    return a>b?a:b; }int min(int a,int b){    return a<b?a:b; }int cmp(const P& a,const P& b){    if(a.l<b.l) return 1;    else if(a.l==b.l&&a.w<b.w) return 1;    else return 0;  }int dp[maxn];int main(){    int T;    scanf("%d",&T);    while(T--)    {         int n;        scanf("%d",&n);        for(int i=0;i<n;i++)        {            int a,b;            scanf("%d%d",&p[i].l,&p[i].w);            a = max(p[i].l,p[i].w);            b = min(p[i].l,p[i].w);             p[i].l = a; p[i].w = b;//长大于宽        }        sort(p,p+n,cmp);        for(int i=0;i<n;i++)        {            dp[i] = 1;            for(int j=0;j<=i;j++)            {                if(p[j].l<p[i].l&&p[j].w<p[i].w)                {                    dp[i] = max(dp[i],dp[j]+1);                 }            }        }        int ans=dp[0];        for(int i=0;i<n;i++)        {            if(ans<dp[i])            ans = dp[i];            }        printf("%d\n",ans);     }    return 0;       }
0 0