例题2 嵌套矩形问题
有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)内。你的任务是选出尽量多的矩形排成一行,使得除了最后一个之外,每一个矩形都可以嵌套在下一个矩形内。如果有多解,矩形编号的字典序应尽量小。
分析:
矩形之间的可嵌套关系是一个典型的二元关系,二元关系可以用图来建模。如果矩形X可以嵌套在矩形Y里,就从X到Y连一条有向边。这个有向图是无环的,因为一个矩形无法直接或间接地嵌套在自己内部。因此,由它构建一个DAG,要求解的便是DAG上的最长路径。
此题中,DAG并未固定起点,因此是不固定起点的最长路径问题。假设d(i)表示从结点i出发的最长路的长度,那么该如何写状态转移方程呢?
d(i) = max{ d(j) + 1 | (i , j)∈E }
第一步只能走到它的相邻点,其中E为边集。因此,首先需要把图建立起来,假设用邻接矩阵保存在矩阵G中,接着就可以考虑用记忆化搜索程序来实现d[i]的计算。事先需要把d数组元素都初始化为0。
int dp(int i) {
int& ans = d[i];
if(ans >0) return ans;
ans = 1;
for(int j=1 ; j<=n ; j++)
if(G[i][j])
ans = max(ans , dp(j) + 1);
return ans;
}
最终答案是所有d(i)中的最大值。
题目还有一个要求:如果有多个最优解,矩形编号的字典顺序应最小。那么选出最大的d[i]值,如果有多个,则选择最小的i。
接下来选择d(i) = d(j) + 1且(i , j) ∈E的任何一个j,为了保证字典顺序,应选择最小的j 。
void print_ans(int i) {
printf("%d" , i);
for(int j =1 ; j<=n ; j++){
if(G[i][j] && d[i] == d[j]+1){
print_ans(j);
break;
}
}
}
完成过程:1.递归过程开始真的看不懂