动态规划--DAG(有向无环图)问题
2018-01-21 16:04
134 查看
1、矩形嵌套问题
问题描述:有n个矩形,每个矩形可以用两个整数a、b描述,表示它的长和宽,矩形X(a,b)可以嵌套在矩形Y(c,d)中,当且仅当a<c,b<d,或者b<c,a<d。现在的任务是选出尽量多的矩形排成一排,使得除了最后一个之外,每个矩形都可以嵌套在下一个矩形中。。。如果有多解,矩形编号的字典序应尽量小。
分析:
矩形之间的可嵌套关系是一个典型的二元关系,二元关系可以用图来建模。如果矩形X可以嵌套在矩形Y中,就从X到Y连一条有向边。这个有向图是无环的,因为一个矩形无法直接或间接的嵌套在自己的内部。换句话说,它是一个DAG,我们要求的便是DAG上的最长路径。状态转移方程如下:其中E代表边集,d(i)表示从节点i出发的最长路长度,状态转移方程的第一步是找到它的相邻节点。
d(i)=max{d(j)+1|(i,j)∈E}
解决方法:
代码如下:首先用邻接矩阵把图保存在矩阵G中(在编写主程序之前需测试和调试程序,以确保建图过程正确无误),接下来编写记忆化搜索程序,调用前初始化数组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值计算出来之后,选择最大的d[i]对应的i,如果有多个i,则选择最小的i,这样才能保证字典序最小,接下来选择d(i)=d(j)+1的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; } }
2、硬币问题
问题描述:有n种硬币,面值分别是V1,V2,......,Vn,每一种硬币的个数有无限多个。给定非负整数S,可以选用多少个硬币,使得面值之和恰好是S?输出硬币数目的最小值和最大值。1<=n<=100,0<=S<=10000,1<=Vi<=S。
分析:
这个问题和嵌套问题的共同点是:本质上也是DAG上的路径问题,将每种面值看作一个点,表示“还需要凑足的面值”,若当前的状态是i,每使用一个硬币j,状态便转移到 i-Vj。不同点是:由于可以把任意矩形放在第一个和最后一个,所以矩形嵌套问题并没有确定路径的起点和终点。而硬币问题的起点是S,终点是0。在上题中,最短序列显然是空,而本题的最短路却不容易确定。
解决方法:
记忆化搜索:
在记忆化搜索中,用数组vis[i]表示状态 i 是否被访问过,以占用一些内存的代价来增程序的可读性。访问数组初始化为memset(vis,0,sizeof(vis))。
int dp(int S) { if(vis[S]) return d[S]; vis[S]=1; int &ans=d[S]; ans=-(1<<30); for(int i=1;i<=n;i++) if(S>=V[i]) ans=max(ans,dp(S-V[i])+1) return ans; }
递推:
本题要求最小和最大值,记忆化搜索就必须写两个,在这种情况下,用递推更加方便。
minv[0]=maxv[0]=0; for(int i=0;i<=S;i++) { minv[i]=INF; maxv[i]=-INF; } for(int i=1;i<=S;i++) { for(int j=1;j<=n;j++) if(i>=V[j]) { minv[i]=min(minv[i],minv[i-V[j]]+1); maxv[i]=max(maxv(maxv[i],maxv[i-V[j]]+1) } }
打印:
输出字典序最小的方案的方法和矩形嵌套类似。
void print_ans(int *d,int S) { for(int i=1;i<=n;i++) if(S>=V[i]&&d[S]==d[S-V[i]) { printf("%d",i); print_ans(d,S-V[i]); break; } }
然后分别调用print_ans(min,S)和print_ans(max,S)即可。
相关文章推荐
- 动态规划 DAG模型 硬币问题
- 【笔试/面试】—— 有向无环图(DAG)的最短路径问题(动态规划)
- DAG上动态规划——巴比伦塔问题
- DAG 动态规划 -- 硬币问题
- 动态规划 DAG问题uva 437 The Tower of Babylon
- 0-1背包问题与完全背包问题C++实现 动态规划
- DAG上的动态规划 - 算法竞赛入门经典 - 嵌套矩形问题
- 算法导论15章 动态规划之矩阵链乘法问题
- 嵌套矩形——DAG上的动态规划
- 石子合并问题 --动态规划--解法1
- 动态规划(DP)之最长上升子序列问题
- 动态规划 背包问题 poj 1837 Balance
- 动态规划(0-1背包问题)
- 动态规划——矩阵连乘的问题
- sdut.acm 2012级《程序设计基础Ⅱ)》_动态规划 数字三角形问题
- Python中运用动态规划解决背包问题
- 动态规划——找零钱问题
- 流水线调度问题——动态规划
- DAG模型的动态规划学习
- 算法设计与分析:第四章 动态规划 4.3多段图的最短路径问题