NYOJ16|嵌套矩形|DP|DAG模型|记忆化搜索

Posted AlenaNuna

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",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\n",MAX);
54     }
55     return 0;
56 }
嵌套矩形

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











以上是关于NYOJ16|嵌套矩形|DP|DAG模型|记忆化搜索的主要内容,如果未能解决你的问题,请参考以下文章

NYOJ 16 矩形嵌套(经典DP)

DAG上的动态规划之嵌套矩形问题

NYOJ - 矩形嵌套(经典dp)

DP入门——DAG上的动态规划

UVA103 dp基础题,DAG模型

ACM-ICPC(9/25)