ACM:DAG上的动态规划------嵌套矩形

来源:互联网 发布:c语言 整数奇偶排序 编辑:程序博客网 时间:2024/05/01 05:15

题目:

有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内。

 

分析:典型的DP题目,把每一个矩形想象成DAG(有向无环图)中的一个点!然后利用DP。。

            状态转移方程:d(i) = max{d(j)+1}    其中(i, j)是DAG中的一条边!  其中d(i)表示从节点(矩形)出发的最长路的长度!

(1)输出字典序最小解

#include <iostream>#include <string>using namespace std;const int MAXN = 1000;int n, x[MAXN], y[MAXN], G[MAXN][MAXN], d[MAXN];int dp(int i) {int &ans = d[i];if(ans > 0) return ans;  //记忆化搜索,如果d[i]已经计算过,就直接返回!ans = 1;for(int j = 0; j < n; ++j) {if(G[i][j]) ans = max(ans, dp(j)+1); //算法核心语句:如果节点i可以到达节点j,那么从节点i出发的最长路 等于 从节点j的最长路 + 1}return ans;  //返回从节点i出发,可以达到的最长路!}void print(int i) {    //以字典序的方式来打印答案!cout << i << endl;for(int j = 0; j < n; ++j) {if(G[i][j] && d[i] == d[j] + 1)  {  //如果找到下一个节点!立马递归调用print()。print(j);break;    //不能忘记break,因为找到下一个点后,没必要再继续找了,不然打印出来的就不止一条路径了!}}}int main() {cin >> n;for(int i = 0; i < n; ++i) {cin >> x[i] >> y[i];if(x[i] > y[i]) {int temp = x[i];x[i] = y[i];y[i] = temp;}}memset(G, 0, sizeof(G));for(int i = 0; i < n; ++i) {for(int j = 0; j < n; ++j) {if(x[i] < x[j] && y[i] < y[j]) {G[i][j] = 1;}}}memset(d, -1, sizeof(d));int ans = 0, best = 0;          //best记录的是最长路的起点!for(int i = 0; i < n; ++i) {if(ans < dp(i)) {ans = dp(i);   //ans记录的是最长路的长度!best = i;}}cout << ans << endl;print(best);cout << endl;return 0;}


(2)如果要打印出所有的最长路的路径,只将break删除是不够的!那样的话,距离相同的点都会全部打印出来!正确的做法是记录路径上的所有点,在递归结束时才一次性输出整条路经。

//输出所有解:#include <iostream>#include <string>using namespace std;const int MAXN = 10000;int x[MAXN], y[MAXN], G[MAXN][MAXN], d[MAXN], n;int dp(int i) {int &ans = d[i];if(ans > 0) return ans;ans = 1;for(int j = 0; j < n; ++j) {if(G[i][j]) {ans = max(ans, dp(j)+1);}}return ans;}int path[MAXN];void print(int cur, int i) {path[cur] = i;if(d[i] == 1) {for(int j = 0; j <= cur; ++j) cout << path[j] << " ";cout << endl;}for(int j = 0; j < n; ++j) {if(G[i][j] && d[i] == d[j] + 1)  print(cur+1, j);}}int main() {cin >> n;for(int i = 0; i < n; ++i) {cin >> x[i] >> y[i];if(x[i] > y[i]) {int temp = x[i];y[i] = x[i];x[i] = temp;}}memset(G, 0, sizeof(G));for(int i = 0; i < n; ++i) {for(int j = 0; j < n; ++j) {if(x[i] < x[j] && y[i] < y[j]) G[i][j] = 1;}}memset(d, -1, sizeof(d));int ans = 0;for(int i = 0; i < n; ++i)  ans = max(ans, dp(i));cout << ans << endl;for(int i = 0; i < n; ++i)  if(ans == dp(i))  print(0, i);cout << endl;return 0;}


 

0 0
原创粉丝点击