题目链接:
http://acm.nyist.net/JudgeOnline/problem.php?pid=16
dp:
设d[i]表示从结点i出发的最长路径长度,状态转移方程为:
d(i) = max{d(j)+1 | (i,j) ∈ E} 其中,E为边集
DAG:
矩形之间的可嵌套关系是一种二元关系,二元关系用图来建模,若X可以嵌套在Y里,则建立一条X指向Y的有向边。
这个有向图是无环的,因为一个矩形无法直接嵌套在自己内部,即此图是一个DAG。求最大的矩形嵌套数,就是求DAG上的最长路径。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 #define clr(c) memset(c, 0, sizeof(c)); 7 8 const int MAXL = 1000+10; 9 typedef struct{ 10 int length; 11 int width; 12 }rectangle; 13 14 rectangle R[MAXL]; // 矩形数组 15 bool G[MAXL][MAXL]; // DAG的邻接矩阵 16 int d[MAXL]; // 状态转移数组 17 int Case, n, num1, num2; 18 19 void CreatGraph(){ // 建图 20 clr(G); 21 for(int i = 0; i < n; i++){ 22 for(int j = 0; j < n; j++){ 23 if(R[i].length < R[j].length && R[i].width < R[j].width){ 24 G[i][j] = true; // i 嵌套在 j 中 25 } 26 } 27 } 28 } 29 30 int dp(int i){ 31 int& ans = d[i]; // 引用 32 if(ans > 0) return ans; 33 ans = 1; 34 for(int j = 0; j < n; j++){ 35 if(G[i][j]) ans = max(ans, dp(j)+1); // dp(j)从j出发的最长路径 36 } 37 return ans; 38 } 39 40 void print_ans(int i){ 41 printf("%d ", i); 42 for(int j = 0; j < n; j++){ 43 if(G[i][j] && d[i] == d[j]+1){ 44 print_ans(j); 45 break; // 字典序最小,第一个符合条件的j输出后即退出 46 } 47 } 48 } 49 50 int main(){ 51 scanf("%d", &Case); 52 while(Case--){ 53 scanf("%d", &n); 54 for(int i = 0; i < n; i++){ // 强行规定长 > 宽 55 scanf("%d%d", &num1, &num2); 56 R[i].length = max(num1, num2); 57 R[i].width = min(num1, num2); 58 } 59 CreatGraph(); 60 clr(d); // 清空状态转移数组 61 int ans = 0, maxAns = 0; 62 for(int i = 0; i < n; i++){ 63 int temp = dp(i); 64 //ans = max(ans, temp); // 输出最大的结果 65 if(temp > ans){ // 输出最大的结果,并记录最大值的编号(若有相同值取最小编号),用于输出路径 66 ans = temp; 67 maxAns = i; 68 } 69 } 70 printf("%d ", ans); 71 //print_ans(maxAns); // 输出路径 72 //printf(" "); 73 } 74 75 return 0; 76 }