1. 程式人生 > >題解【CJOJ1070/UVA】嵌套矩形

題解【CJOJ1070/UVA】嵌套矩形

矩形 name 路徑 names color 模板 c代碼 pan struct

P1070 - 【Uva】嵌套矩形

Description

有 n 個矩形,每個矩形可以用兩個整數 a, b 描述,表示它的長和寬。矩形 X(a, b) 可以嵌套在矩形 Y(c, d) 中當且僅當 a<c, b<d,或者 b<c, a<d(相當於把矩形 X 旋轉了 90°)。例如 (1, 5) 可以嵌套在 (6, 2) 內,但不能嵌套在 (3, 4) 內。
你的任務是選出盡量多的矩形,使得除了最後一個之外,每一個矩形都可以嵌套在下一個矩形內。

Input

第一行一個正整數 n (n <= 1000)。
接下來 n 行每行兩個正整數 a, b 表示矩形 i 的長和寬。

Output

第一行一個整數 k 表示符合條件的最多矩形數。
第二行 k 個整數依次表示符合條件矩形的編號,要求字典序最小。

Sample Input

8
14 9
15 19
18 12
9 10
19 17
15 9
2 13
13 10

Sample Output

4
4 8 3 2

Hint

最大嵌套深度為 4 。
4 個矩形分別是:4(9, 10) < 8(13, 10) < 3(18,12) < 2(15,19)

Source

入門經典,DP,DAG(有向無環圖)

此題是最長路模板。

最長路可以用DP來求,具體實現過程是這樣的:

inline int DP(int p)
{
    if(dp[p]>0)//特判
    {
        return dp[p];
    }

    dp[p]=1;//初值

    for(register int j=1; j<=n; j++)//枚舉所有出邊
    {
        if(m[p][j]==1)//如果有邊
        {
            dp[p]=max(dp[p],DP(j)+1);//就進行DP
} } return dp[p];//返回 }

有了這個模板,此題就非常好做了:

  先預處理處所有相連接的邊,然後進行DP,最後統計答案。

AC代碼:

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 inline int read()//快速讀入
  6 {
  7     int f=1,x=0;
  8     char c=getchar();
  9 
 10     while(c<0 || c>9)
 11     {
 12         if(c==-)f=-1;
 13         c=getchar();
 14     }
 15 
 16     while(c>=0 && c<=9)
 17     {
 18         x=x*10+c-0;
 19         c=getchar();
 20     }
 21 
 22     return f*x;
 23 }
 24 
 25 struct Node
 26 {
 27     int x,y;
 28 } a[1005];
 29 int n,dp[1005],m[1005][1005],sum=-1;
 30 
 31 inline int check(Node w,Node q)//預處理處矩形是否嵌套
 32 {
 33     if(w.x<q.x && w.y<q.y)return 1;
 34 
 35     if(w.y<q.x && w.x<q.y)return 1;
 36 
 37     return 0;
 38 }
 39 
 40 inline int DP(int p)//DP主過程
 41 {
 42     if(dp[p]>0)
 43     {
 44         return dp[p];
 45     }
 46 
 47     dp[p]=1;
 48 
 49     for(register int j=1; j<=n; j++)
 50     {
 51         if(m[p][j]==1)
 52         {
 53             dp[p]=max(dp[p],DP(j)+1);
 54         }
 55     }
 56 
 57     return dp[p];
 58 }
 59 
 60 inline void print(int ans)
 61 {
 62     printf("%d ",ans);//輸出當前邊
 63 
 64     for(register int i=1; i<=n; i++)//枚舉所有出邊
 65     {
 66         if(m[ans][i]==1 && dp[ans]==dp[i]+1)//如果有邊
 67         {
 68             print(i);//遞歸輸出
 69 
 70             break;
 71         }
 72     }
 73 }
 74 
 75 int main()
 76 {
 77     memset(dp,-1,sizeof(dp));
 78     memset(m,-1,sizeof(m));
 79 
 80     n=read();
 81 
 82     for(register int i=1; i<=n; i++)
 83     {
 84         a[i].x=read(),a[i].y=read();
 85     }
 86 
 87     for(register int i=1; i<=n; i++)
 88     {
 89         for(register int j=1; j<=n; j++)
 90         {
 91             if(check(a[i],a[j]))
 92             {
 93                 m[i][j]=1;//連邊
 94             }
 95         }
 96     }
 97 
 98     for(register int i=1; i<=n; i++)//計算各邊長度
 99     {
100         if(dp[i]==-1)
101         {
102             dp[i]=DP(i);
103         }
104     }
105 
106     for(register int i=1; i<=n; i++)//統計答案
107     {
108         if(dp[i]>dp[sum])
109         {
110             sum=i;
111         }
112     }
113 
114     printf("%d\n",dp[sum]);//輸出總數
115 
116     print(sum);//打印路徑
117 
118     return 0;
119 }

題解【CJOJ1070/UVA】嵌套矩形