zoukankan      html  css  js  c++  java
  • NYOJ16|嵌套矩形|DP|DAG模型|记忆化搜索

    矩形嵌套

    时间限制:3000 ms  |  内存限制:65535 KB
    难度:4
     
    描述
    有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内。
     
    输入
    第一行是一个正正数N(0<N<10),表示测试数据组数,
    每组测试数据的第一行是一个正正数n,表示该组测试数据中含有矩形的个数(n<=1000)
    随后的n行,每行有两个数a,b(0<a,b<100),表示矩形的长和宽
    输出
    每组测试数据都输出一个数,表示最多符合条件的矩形数目,每组输出占一行
    样例输入
    1
    10
    1 2
    2 4
    5 8
    6 10
    7 9
    3 1
    5 8
    12 10
    9 7
    2 2
    
    样例输出
    5

    对于这道题目,我们可以有两种写法。
    第一种写法:(DP+快速排序)
    因为题目要我们选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内,而矩形又有长和宽两个因素。我们就可以开一个结构体来存储每一个
    矩形的长和宽,读入时判断一下长和宽的大小,保证长小于宽,以便我们后边进行快速排序。接着快速排序一遍,写一个比较函数把每一个矩形的长按照从大到小排序。接下来我们
    就可以直接DP了。
    注意:MAX的初值应设为1,因为当没有矩形可以互相嵌套时,就不会触发if (NODE[k].A<NODE[j].A&&NODE[k].B<NODE[j].B),自然也不会更新到MAX值。而当没有矩形可以互相
    嵌套时,符合条件的矩形数为1,所以MAX初值应该设置为1,这样才可以保证输出的答案是有效的。
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 using namespace std;
     7 int read()
     8 {
     9     int f=1,x=0; char c=getchar();
    10     while (c>'9'||c<'0') {if (c=='-') f=-1; c=getchar();}
    11     while (c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    12     return x*f;
    13 }
    14 struct node
    15 {
    16     int A;
    17     int B;
    18 }NODE[1110];
    19 bool comp(const node&a,const node&b)
    20 {
    21     if (a.A==b.A) return a.B<b.B;
    22     return a.A<b.A;
    23 }
    24 int T,N,F[1110],MAX;
    25 int main()
    26 {
    27     T=read(); 
    28     for (int i=1; i<=T; i++) {
    29         MAX=1;
    30         N=read();
    31         for (int j=1; j<=N; j++) F[j]=1;
    32         for (int j=1; j<=N; j++) {
    33             NODE[j].A=read();
    34             NODE[j].B=read();
    35             if (NODE[j].A>NODE[j].B) {
    36                 int t=NODE[j].A;
    37                 NODE[j].A=NODE[j].B;
    38                 NODE[j].B=t;
    39             }
    40         }
    41         sort(NODE+1,NODE+N+1,comp);
    42         for (int j=2; j<=N; j++)
    43         for (int k=1; k<j; k++)
    44         if (NODE[k].A<NODE[j].A&&NODE[k].B<NODE[j].B) {
    45             if (F[k]+1>F[j]) F[j]=F[k]+1;
    46             if (F[j]>MAX) MAX=F[j];
    47         }
    48         printf("%d
    ",MAX);
    49     }
    50     return 0;
    51 }
    矩形嵌套

    第二种写法:(DP+DAG模型+记忆化搜索)

    Tips:DAG:有向无环图。由于一个矩形无法直接或间接地嵌套到自己的内部,所以这个有向图是无环的。

    这种写法是紫书上推荐的,所以网络上的代码大多是这种写法。我们还是开一个结构体来存储每一个矩形的长和宽,然后就两重循环枚举每两个矩形之间是否可以嵌套,如果可以嵌套,

    就将G[i][j]标记为1,意味着i到j有边相连。然后DFS记忆化搜索每一个矩形(实际上就是每一个点,因为我们已经把矩形间的嵌套关系建模成DAG了,自然每一个矩形都变成了DAG中的

    每一个点。),我这里用的DFS是有返回值的,而不是一个纯过程,DFS(NUM)返回的是从NUM点出发的最长路径,也就是最多可以嵌套的矩形个数。然后找出最长路径,记录下来,就

    是答案了。

    我这里还是想讲一讲这个记忆化搜索的函数,打一下批注以助于理解。

    int DFS(int NUM)//寻找NUM点出发的最长路径
    {
      int SP=1;//注意:SP要定义在函数里,这样子两层递归之间的SP才不会互相伤害。 SP用于记录当层NUM点出发的最长路径长度。
      if (BOOK[NUM]>0) return BOOK[NUM];//BOOK[NUM]存储着NUM点出发的最长路径。如果BOOK[NUM]>0,这就意味着NUM点出发的最长路径已经被确定了,也就没有必要继续搜索

    NUM点出发的最长路径了,就直接返回NUM点出发的最长路径,作为上一层需要的答案组成之一。
      for (int i=1; i<=N; i++)
      if (G[NUM][i]) SP=la(SP,DFS(i)+1);//如果NUM点和i点之间是连通的,SP=max(SP,DFS(i)+1),这一点运用的思想与DP一样,不作解释。
      BOOK[NUM]=SP;//搜索完当层NUM点出发的最长路径,就标记下去。
      return SP;
    }

    记忆化搜索的核心就是标记和搜索,标记已经搜索过的部分和内容,下一次再到这里时就不需要再耗时搜索一遍,因为结果已经确定了,所以直接返回结果就可以。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 using namespace std;
     7 int read()
     8 {
     9     int f=1,x=0; char c=getchar();
    10     while (c>'9'||c<'0') {if (c=='-') f=-1; c=getchar();}
    11     while (c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    12     return x*f;
    13 }
    14 struct node
    15 {
    16     int A;
    17     int B;
    18 }NODE[1110];
    19 int T,N,MAX=1,F[1100],SP;
    20 bool G[1100][1100];
    21 int BOOK[1100];
    22 int la(int A,int B)
    23 {
    24     if (A>B) return A;
    25     return B;
    26 }
    27 int DFS(int NUM)
    28 {
    29     int SP=1;
    30     if (BOOK[NUM]>0) return BOOK[NUM];
    31     for (int i=1; i<=N; i++)
    32     if (G[NUM][i]) SP=la(SP,DFS(i)+1);
    33     BOOK[NUM]=SP;
    34     return SP;
    35 }
    36 int main()
    37 {
    38     T=read();
    39     while (T--) {
    40         MAX=1;
    41         memset(BOOK,0,sizeof(BOOK));
    42         memset(G,0,sizeof(G));        
    43         N=read();
    44         for (int i=1; i<=N; i++) {
    45             NODE[i].A=read(); NODE[i].B=read();
    46         }
    47         for (int i=1; i<=N; i++)
    48         for (int j=1; j<=N; j++)
    49         if ((NODE[i].A<NODE[j].A&&NODE[i].B<NODE[j].B)||
    50             (NODE[i].A<NODE[j].B&&NODE[i].B<NODE[j].A)) G[i][j]=1;
    51         for (int i=1; i<=N; i++) 
    52         if (DFS(i)>MAX) MAX=DFS(i);
    53         printf("%d
    ",MAX);
    54     }
    55     return 0;
    56 }
    嵌套矩形

    有问题可以直接在评论里面提问,有需要转载的请得到我的允许,否则按侵权处理。

  • 相关阅读:
    python
    redis
    mongodb replica on aws ec2
    mysql
    java正则表达式
    终端make命令和Git学习
    linux和shell学习
    centos普通用户安装jenkins
    centos7普通用户安装jdk
    WPF动画
  • 原文地址:https://www.cnblogs.com/AlenaNuna/p/7350581.html
Copyright © 2011-2022 走看看