DAG上动态规划

很多动态规划问题都可以转化为DAG上的最长路,最短路,或路径计数问题。

硬币问题:

有N中硬币,面值分别为v1,v2,v3,……vn,每种都无穷多,给定非负整数S,可以选用多少个硬币,使他们的总和恰好为S。输出硬币数目的最小值和最大值。

解:每种面值看作一个点,表示:还需要凑足的面值。则开始状态为S,目标状态为0;若当前状态为i,当使用硬币j后,状态转为i-v[j].

代码说明好了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <string>
 7 #include <vector>
 8 #include <set>
 9 #include <map>
10 #include <queue>
11 #include <stack>
12 using namespace std;
13 const int INF = 0x7fffffff;
14 const double EXP = 1e-8;
15 const int MS = 100005;
16 int minv[MS], maxv[MS];
17 int V[MS];
18 int main()
19 {
20     fill(minv, minv + MS, INF);
21     fill(maxv, maxv + MS, -INF);
22     minv[0] = maxv[0] = 0;
23     int N, S;
24     cin >> N >> S;
25     for (int i = 1; i <= N; i++)
26         cin >> V[i];
27
28     for (int i = 1; i <= S; i++)
29         for (int j = 1; j <=N;j++)
30             if (i >= V[j])
31             {
32                 minv[i] = min(minv[i], minv[i - V[j]] + 1);
33                 maxv[i] = max(maxv[i], maxv[i - V[j]] + 1);
34             }
35     cout << minv[S] << " " << maxv[S] << endl;
36     return 0;
37 }

输出字典序最小的方案:

 1 void print_ans(int *d, int s)
 2     {
 3         for (int i = 1; i <= n;i++)
 4             if (s >= v[i] && d[s] == d[s - v[i]] + 1)
 5             {
 6                 cout << i << " ";
 7                 print_ans(d, s - v[i]);
 8                 break;
 9             }
10     }
11     print_ans(minv, S);
12     cout << endl;
13     print_ans(maxv, S);

另一种方法求字典序最小的方案。

用min_coin[i]来记录状态为i时,最小的j,满足d[j]+1=d[i];

code:

 1 for (int i = 1; i <= S; i++)
 2         for (int j = 1; j <= n; j++)
 3         {
 4             if (i > =v[j])
 5             {
 6                 if (minv[i] > minv[i - v[j]] + 1)  //如果j从大到小   则>=
 7                 {
 8                     minv[i] = minv[i - v[j]] + 1;
 9                     min_coin[i] = j;
10                 }
11                 if (maxv[i] < maxv[i - v[j]] + 1)  //如果j从大到小,则<=
12                 {
13                     maxv[i] = maxv[i - v[j]] + 1;
14                     max_coin[i] = j;
15                 }
16             }
17         }
18     void print_ans(int *d, int S)
19     {
20         while (S)
21         {
22             cout << d[S] << " ";
23             s -= v[d[s]];
24         }
25     }
26     print_ans(min_coin, S);
27     cout << endl;
28     print_ans(max_coin, S);

问题二:矩形嵌套。

矩形的长宽为a,b;设一个矩形的长宽为a,b,另一个矩形长宽为c,d;当a<c&&b<d  或 b<c&&a<d时,两个矩形可以嵌套。

现在给出N个矩形,嵌套组合为第一个嵌套在第二个,第二个可以嵌套在第三个,第三个可以嵌套在第四个,……。

求数量多的嵌套组合的个数。

解:DAG 法。每个矩形抽象为一个点,当矩形a可以嵌套在矩形b时,我们在a,b之间连一条边。那么问题转化为求DAG上的最长路径。

设d[i]为从节点i出发的最长路径,则有d[i]=max(d[j]+1),   (i,j)是一条边。

 1 //记忆化搜索
 2     int d[MS];
 3     int dp(int i)
 4     {
 5         int &ans = d[i];
 6         if (ans > 0)
 7             return ans;
 8         ans = 1;
 9         for (int j = 1; j <= n; j++)
10             if (G[i][j])
11                 ans = max(ans, dp(j)+ 1);
12         return ans;
13     }

输出字典序最小的方案:

 1 void print_ans(int i)   //  d[i]==max  &&  i is smallest
 2     {
 3         cout << i << " ";
 4         for (int j = 1; j <= n; j++)
 5         {
 6             if (G[i][j] && d[i] == d[j] + 1)
 7             {
 8                 print_ans(j);
 9                 break;
10             }
11         }
12     }
时间: 2024-11-05 13:36:49

DAG上动态规划的相关文章

UVA_437_The_Tower_of_the_Babylon_(DAG上动态规划/记忆化搜索)

描述 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=378 n种方块,给出每一种的长宽高,现在要落起来,上面的方块的长和宽要严格小于下面的方块,问最多落多高. ACM Contest Problems ArchiveUniversity of Valladolid (SPAIN)437 The Tower of BabylonPerhap

ACM:DAG上的动态规划------硬币问题

ExecutorService 建立多线程线程池的步骤: 线程池的作用: 线程池作用就是限制系统中执行线程的数量. 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪费了系统资源,多了造成系统拥挤效率不高.用线程池控制线程数量,其他线程排队等候.一个任务执行完毕,再从队列的中取最前面的任务开始执行.若队列中没有等待进程,线程池的这一资源处于等待.当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了:否则进入等待队列. 为什么要用线程池: 1.减少了创建和

UVa 103 Stacking Boxes --- DAG上的动态规划

UVa 103 题目大意:给定n个箱子,每个箱子有m个维度, 一个箱子可以嵌套在另一个箱子中当且仅当该箱子的所有的维度大小全部小于另一个箱子的相应维度, (注意箱子可以旋转,即箱子维度可以互换),求最多能套几个箱子. 第一行输入为n,m,之后是n行m维的箱子 解题思路:嵌套关系是二元关系,因此这题即在DAG上做动态规划, 只不过将二维的判断改成了n维,其他不变. 详细看考:DAG上的动态规划之嵌套矩形  (ps:这题可以理解成嵌套m边形) /* UVa 103 Stacking Boxes --

DP入门(2)——DAG上的动态规划

有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题:有n个矩形,每个矩形可以用两个整数a.b描述,表示它的长和宽.矩形X(a , b)可以嵌套在矩形Y(c , d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋转90°).例如(1,5)可以嵌套在(6, 2)内,但不能嵌套在(3, 4)内.你的任务是选出尽可能多的矩形排

嵌套矩形——DAG上的动态规划

有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 题目描述: 有n个矩形,每个矩形可以用两个整数a,b描述,表示它的长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋转90°).例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)内.你的任务是选出尽可能多的矩形排成一行.使得除了最后一个之外,每个矩形都

Monkey and Banana(DAG上的动态规划问题)

Monkey and Banana Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 8122    Accepted Submission(s): 4194 Problem Description A group of researchers are designing an experiment to test the IQ of a

The Tower of Babylon UVA - 437 DAG上的动态规划

题目:题目链接 思路:每个方块可以用任意多次,但因为底面限制,每个方块每个放置方式选一个就够了,以x y为底 z 为高,以x z为底 y 为高,以y z为底 x为高,因为数据量很小,完全可以把每一种当成DAG上的一个结点,然后建图找最长路径. AC代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cs

[CF225C] Barcode (简单DAG上dp)

题目链接:http://codeforces.com/problemset/problem/225/C 题目大意:给你一个矩阵,矩阵中只有#和.两种符号.现在我们希望能够得到一个新的矩阵,新的矩阵满足每一列都只有一种符号,并且连续相同符号的列数在区间[x,y]之间. 解: 现将列中的点统计出来,然后就是枚举把列数在x到y之间的需要更改为点的统计出来.这些点染上白色. 然后再将列数在x到y之间的需要更改为井号的点数统计出来,这些点染成黑色. 接下来就是DAG上的动态规划了,dp[i]代表从i到终点

UVA - 10131Is Bigger Smarter?(DAG上的DP)

题目:UVA - 10131Is Bigger Smarter? (DAG) 题目大意:给出一群大象的体重和IQ.要求挑选最多的大象,组成一个序列.严格的体重递增,IQ递减的序列.输出最多的大象数目和这些大象的序列(当中一种就能够). 解题思路:DAG上的DP.和之前的一篇相似.uva437 - The Tower of Babylon(DAG上的DP).就是将每两仅仅大象满足上面的序列要求的形成一条有向边. 之后就是DAG上的DP.然后再路径输出. 代码: #include <cstdio>