dp题目思路理解 (嵌套镶嵌问题DAG)
来源:互联网 发布:域名可以干什么 编辑:程序博客网 时间:2024/05/29 18:25
- 输入
- 第一行是一个正正数N(0<N<10),表示测试数据组数,
每组测试数据的第一行是一个正正数n,表示该组测试数据中含有矩形的个数(n<=1000)
随后的n行,每行有两个数a,b(0<a,b<100),表示矩形的长和宽 - 输出
- 每组测试数据都输出一个数,表示最多符合条件的矩形数目,每组输出占一行
- 样例输入
1101 22 45 86 107 93 15 812 109 72 2
- 样例输出
5
若x能镶嵌于y时,x与y就有一条有向边,并且是不可能存在环的;
dp最重要的是状态和状态转移方程,可以从以下考虑:
1)状态:如果dp(i)表示最多能镶嵌几层,那么我们就要求dp(0);
2)状态如何转移或者说有哪些决策,我们在这个状态下能做什么:显而易见,我们只能顺着有向边走,即找个比当前矩形大的走,dp(i)-->dp(j) |(i,j)∈E;
3)对当前状态来说,那么多决策选哪个好:当然是最大的好,求的就是最大值,每一步都求最大,那么总的肯定最大,有点像贪心;
综上 dp(i)=max{dp(j)+1|(i,j)∈E}; 注:dp(i)的值用个数组保存;
我觉得对于dp还有一种思路理解:
若将所有有向边的画出来,就是一棵树;
我们要求得就是根的最大树高;
同时对于每一层节点来说他们的高度取决于他们最高的子树的高度+1;
所以将dp(i)想象成第i个节点的最大高度就好;
那么状态转移方程也可以那么想:dp(i)=max{dp(j)+1|(i,j)∈E}; i节点的树高就是他儿子中最高的那个+1;
dp有两种方法
1)递推方法(一般两个for循环,外面那个for是1~状态数,里面那个for是1~决策总数)
从终点出发回到起点,也即是从树的单子叶节点出发,逆着层序遍历回到根,那么对于每一节点的高就十分简单就推出来,好比数塔问题就是这样;
2)记忆化搜索(一般递归函数)
从起点(根)出发,即一个状态出发,取最有利的路走到下一状态;
dp简单来说就是每种路径都走一遍,得出最有利的路径,便走这条路;
至于路径打印就逆着推就好了;根据d[i],因为走一步就+1,所以比d[i]小1的肯定就是i的下一步;
下面是该题目的代码:
#include<iostream>#include<cstring>#include<algorithm>using namespace std;int d[500],G[50][50],n;struct Rectangle{int x;int y;Rectangle(int x=0,int y=0):x(x),y(y) {}};ostream& operator << (ostream& out,const Rectangle A){out << "(" << A.x <<','<<A.y<<')';}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;}void print_ans(int i){cout<<i<<' ';for(int j=0;j<n;j++)if(G[i][j]&&d[i]==d[j]+1){print_ans(j);break;}}void print(int *A,int m) //打印最小字典序的答案 {for(int i=0;i<m;i++)cout<<A[i]<<' ';putchar('\n');}void print_allans(int *A,int i,int cur) //打印所有答案 {A[cur]=i;if(d[i]==1){print(A,cur+1);}else for(int j=0;j<n;j++){if(G[i][j]&&d[i]==d[j]+1){print_allans(A,j,cur+1);}}}bool operator < (Rectangle A,Rectangle B) {if((A.x<B.x&&A.y<B.y)||(A.y<B.x&&A.x<B.y)) return true;return false;}int main(){int k;Rectangle R[500];cin>>k;while(k--){memset(d,0,sizeof(d));memset(G,0,sizeof(G));cin>>n;int m=n;int i=0;while(m--){cin>>R[i].x>>R[i].y;i++;}for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(i!=j&&R[i]<R[j]) G[i][j]=1;sort(R,R+n); cout<<dp(0);//int a[100];//print_allans(a,0,0);//print_ans(0);if(k) cout<<endl;}}
接下来系统总结一下:
状态有两种实现方法:1)设d(i)为从i点出发的最长路,则d(i)=max{dp(j)+1|(i,j)∈E}; 即 从前往后,起点出发;
2)设d(i)为从i点结束的最长路,则d(i)=max{dp(j)+1|(j,i)∈E}; 即 从后往前,终点出发;
实现方法: 1)记忆化搜索:上面的状态1)法,正着递推,也即是填表法:对于每一个状态i,找到f(i)依赖的所有状态; 如:f(i) 的值要靠f(Vj)算 出来,其中Vj为i的相连点,于是去算f(Vj);
2)递推:上面的状态2)法,反着递推,也称为刷表法:是从Vj到i ,是因为每个d[Vj]会影响到d[i]的数值,所以“对于每个状态i,更 新f(i)所影响到的状态”,类似Dijkstra 更新i点周围所有相邻点Vj的d[Vj]值;
- dp题目思路理解 (嵌套镶嵌问题DAG)
- DAG问题之矩形嵌套
- NYoj16 矩形嵌套 DAG上的Dp
- 嵌套矩形 DAG上的dp(深搜+dp)
- DAG模型—嵌套矩形问题
- HPUoj 1084: 矩形嵌套问题( DAG/LIS
- DAG上的DP之 —— 矩形嵌套
- NYOJ 16 矩形嵌套 (DAG上的DP)
- NYOJ 16 矩形嵌套(DAG上的DP)
- nyoj 16 矩形嵌套(DAG上的dp)
- nyoj 16 矩形嵌套 (DAG上的DP)
- NYOJ 16 矩形嵌套 DAG或排序+DP
- bzoj4976宝石镶嵌 DP
- [bzoj4976][dp]宝石镶嵌
- 矩阵嵌套问题(DAG上的动态规划)
- uva 103(DAG,嵌套)
- DAG模型 矩形嵌套
- DAG模型-嵌套矩阵
- oracle11gRAC环境使用RMAN备份方案
- Android之shape属性详解
- 丑数<数学技巧>
- android stuido 常见错误整理
- Java大数 HDU1042 + 斐波那契数列
- dp题目思路理解 (嵌套镶嵌问题DAG)
- 《 常见算法与数据结构》符号表ST(1)——基本介绍
- java传统线程介绍
- SAP ABAP如何隐藏你写的程序代码(危险,请小心谨慎)
- Java各种常用时间转换
- mavn pom 配置
- AndroidStudio配置指南总结
- java String 两种不同的赋值 比较
- bp神经网络 原理及代码