题目描述:
有n个矩形,每个矩形可以用两个整数来描述,表示它的长与宽。矩形X(a, b) 可以嵌套在矩形 Y(c, d) 中,当且仅当 a < c, b< d 或者 b < c, a < d (矩阵可以旋转90度)。你的任务是选出尽可能多的矩阵排成一行,使得每一个矩形(除最后一个矩阵)都可以嵌套在后一个矩形内。
注:如果有多解,矩形编号的数字尽量小。
解题思路:
这个题是DAG(有向无环图)上的最长路经问题。这个题是要我们求不固定起点的最长路经。
我们可以用动态规划来做,令d [ i ] 为从第i个矩形出发最长路长度。
可写出状态转移方程: d[ i ] = max( d[ i ] , dp( j ) + 1 )
要输出字典序最小的解,只需每次找寻下一个解的时候,从第一个矩形开始循环即可。
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #define MAX 100 using namespace std; struct mat{ int l,w; }; mat a[MAX]; int G[MAX][MAX]; int d[MAX]; int T,n; int dp(int i){ if(d[i]) return d[i]; d[i] = 1;//不要忘记这一步 for(int j = 1; j <= n; j++) if(G[i][j]) d[i] = max(d[i],dp(j)+1); return d[i]; } void display(int i){ cout<<i<<" "; for(int j = 1; j <= n; j++){ if(G[i][j] && d[i] == d[j] + 1){ display(j); return; } } } int main() { scanf("%d", &T); while(T--){ memset(G,0,sizeof(G)); memset(d,0,sizeof(d)); scanf("%d", &n); for(int i=1;i<=n;i++){ scanf("%d %d",&a[i].l, &a[i].w); for(int j=1;j<i;j++) if((a[j].l < a[i].l && a[j].w < a[i].w)|| (a[j].l < a[i].w && a[j].w < a[i].l)) G[j][i] = 1;//j 可以被 i 覆盖 else if((a[j].l > a[i].l && a[j].w > a[i].w)|| (a[j].l > a[i].w && a[j].w > a[i].l)) G[i][j] = 1; }//DAG矩阵 G 构建完成 int max_i = 0; for(int i=1;i<=n;i++) if(dp(max_i) < dp(i)) max_i = i; cout<<d[max_i]<<endl; display(max_i); } return 0; }