题目:
有 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
分析与解答:
DAG意思是有向无环图,所谓有向无环图是指任意一条边有方向,且不存在环路的图
矩形之间的“可嵌套”关系是一个典型的二元关系,二元关系可以用图来建模。如果矩 形X可以嵌套在矩形Y里,就从X到Y连一条有向边。这个有向图是无环的,因为一个矩形无 法直接或间接地嵌套在自己内部。换句话说,它是一个DAG。这样,所要求的便是DAG上 的最长路径。
方法
仿照数字三角形的做 法,设d(i)表示从结点i出发的最长路长度,第一步只能走到它 的相邻点,状态转移方程:d(i) = max { d(j) + 1 | (i,j) ∈E)
最终答案是所有d(i)中的最大值。
要先把图建立出来,假设用邻接矩阵保存在 矩阵G中。接下来编写 记忆化搜索程序(调用前需初始化d数组的所有值为0):
思考总结
1.
他初始化为0,我初始化为-1,如果矩阵的边相等,那么我是没有对这个邻接矩阵赋值的,因此,刘汝佳的代码不能直接套用,必须加上==1
2.
大家看题:除了最后一个之外,每一个矩形都可以嵌套在下一个矩形内。
我们邻接矩阵是根据 矩形X可以嵌套在矩形Y里,就从X到Y连一条有向边来建立的
说明最后一个一定是大矩形
那么打印出来就是由小矩形到大矩形的,
d(i)表示从结点i出发的最长路长度
这个路是以那个最大矩形为终止点的
那我们写dfs递归的意思是,d(i)嵌套在d(j)里,(d(i)比d(j)小),同时d(j)到最大矩形的距离最大
如果有多个最优解,矩形编号的字典序应最小。将所有d值计算出来以后,选择最最大d[i]所对应的i。如 果有多个i,则选择最小的i,这样才能保证字典序最小。接下来可以选择d(i)=d(j)+1且 (i,j)∈E的任何一个j。为了让方案的字典序最小,应选择其中最小的j
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;const int maxN=2000;int n;
int A[maxN];
int B[maxN];
int G[maxN][maxN];
int F[maxN];int dfs(int x);
void print_ans(int ans);int main()
{memset(F,-1,sizeof(F));memset(G,-1,sizeof(G));cin>>n;for (int i=1;i<=n;i++){cin>>A[i]>>B[i];}for (int i=1;i<=n;i++)for (int j=1;j<=n;j++)if (((A[i]<A[j])&&(B[i]<B[j]))||((A[i]<B[j])&&(B[i]<A[j])))G[i][j]=1;for (int i=1;i<=n;i++)if (F[i]==-1)F[i]=dfs(i);int Ans=0;for (int i=1;i<=n;i++)if (F[i]>F[Ans])Ans=i;cout<<F[Ans]<<endl;print_ans(Ans);cout<<endl;return 0;
}int dfs (int i){int & ans=F[i];if(ans>0) return ans;ans=1;for(int j=1;j<=n;++j){if(G[i][j]==1) ans=max(ans,dfs(j)+1);} return ans;
}void print_ans(int i){printf("%d ",i);for(int j=1;j<=n;++j){//选最小的j if(G[i][j]==1&&(F[i]==F[j]+1)){print_ans(j);break;} }
}