动态规划4.4——背包问题
题目上添加了超链接,大家点一下题目就会自动跳转到Poj原题界面~~ 冲鸭冲鸭ヾ(◍°∇°◍)ノ゙。
前言:
建议大家按随笔顺序阅览,背包问题是一类很经典的动态规划问题,知识涵盖可以占常见动态规划类型里的10%。
由于前辈们总结的太好,现在基本上见不到单纯的模板背包问题了,命题人多会结合一些其他知识点进行综合考察,当然背包问题本身就涉及了许多不同的算法。之前有用心写过一篇关于背包问题的随笔,(点我)这里就直接给大家送上链接了。想要大家看一下(羞赧)。
动态规划组成部分:
1:确定状态
—确定最后一步(最优策略)
—抽象子问题
2:归纳转移方程
3:初始条件和边界情况
4:计算顺序
4.4.1 Charm Bracelet (3624)
题意:n个物品,每个物品有w和d属性,要求选出一定的物品,在Σw不超过m的情况下,使得Σd最大。
小笔记:01背包问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <cstdio> using namespace std; #define MAX(a, b) (a > b ? a : b) int F[15000], V; //0-1背包,其中c为费用,w为价值,V为最大容量 void zeroonePack( int c, int w) { for ( int v = V; v >= c; v--) F[v] = MAX(F[v], F[v - c] + w); } int main() { int n; scanf ( "%d%d" , &n, &V); while (n--) { int w, d; scanf ( "%d%d" , &w, &d); zeroonePack(w, d); //本题中对应的费用为w,价值为d } printf ( "%d\n" , F[V]); return 0; } |
4.4.2 Piggy-Bank (1384)
题意:n种不同的硬币,有两个属性,p代表价值,w代表重量,钱罐空时重e,满时重f,计算满时钱罐里最小可能的价值是多少。
小笔记:完全背包问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <cstdio> #include <algorithm> using namespace std; const int INF = 0x3f3f3f3f; int V, F[10001]; //完全背包,其中c为费用,w为价值,V为最大容量 void completePack( int c, int w) { for ( int v = c; v <= V; v++) F[v] = min(F[v], F[v - c] + w); } int main() { int t; scanf ( "%d" , &t); while (t--) { int e, f, n; scanf ( "%d%d%d " , &e, &f, &n); scanf ( "" ); V = f - e; fill(F + 1, F + V + 1, INF); while (n--) { int p, w; scanf ( "%d%d" , &p, &w); completePack(w, p); //本题中对应的费用为w,价值为p } if (F[V] == INF) printf ( "This is impossible.\n" ); else printf ( "The minimum amount of money in the piggy-bank is %d.\n" , F[V]); } return 0; } |
4.4.3 Cash Machine (1276)
题意:有n台提款机,每台提款机提供货币的不同的面值和数量,求这些机器能提取的不超过指定限额的最大金额。
小笔记:多重背包问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include <cstdio> #include <algorithm> using namespace std; const int N = 100001; int V; //指定限额的最大金额 int F[N]; void zeroonePack( int c, int w) { for ( int v = V; v >= c; v--) F[v] = max(F[v], F[v - c] + w); } void completePack( int c, int w) { for ( int v = c; v <= V; v++) F[v] = max(F[v], F[v - c] + w); } //多重背包,其中c为费用,w为价值,m为数量 void multiplePack( int c, int w, int m) { if (c * m >= V) { completePack(c, w); return ; } int k = 1; while (k < m) { zeroonePack(k * c, k * w); m -= k; k <<= 1; } zeroonePack(m * c, m * w); } int main() { int n; while (~ scanf ( "%d%d" , &V, &n)) { fill(F, F + N, 0); while (n--) { int m, d; scanf ( "%d%d" , &m, &d); multiplePack(d, d, m); //本题中费用和价值都是d,对应数量为m } printf ( "%d\n" , F[V]); } return 0; } |
4.4.4 Coins (1742)
题意:有n种硬币,每种硬币具有不同的面值和个数,问可以组成1…m中多少个面值。
小笔记:多重背包问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include <cstdio> #include <algorithm> using namespace std; const int N = 100001; int V, F[N]; void zeroonePack( int c, int w) { for ( int v = V; v >= c; v--) if (F[v] < F[v - c] + w) F[v] = F[v - c] + w; } void completePack( int c, int w) { for ( int v = c; v <= V; v++) if (F[v] < F[v - c] + w) F[v] = F[v - c] + w; } void multiplePack( int c, int w, int m) { if (c * m >= V) { completePack(c, w); return ; } int k = 1; while (k < m) { zeroonePack(k * c, k * w); m -= k; k <<= 1; } zeroonePack(m * c, m * w); } int main() { int n; while ( scanf ( "%d%d" , &n, &V) && (n || V)) { fill(F, F + N, 0); F[0] = 1; int a[101], c[101]; for ( int i = 0; i < n; i++) scanf ( "%d" , &a[i]); for ( int i = 0; i < n; i++) scanf ( "%d" , &c[i]); for ( int i = 0; i < n; i++) multiplePack(a[i], 0, c[i]); //本题费用对应a,数量对应c,因为只涉及面值,不涉及每种硬币的价值,所以不考虑w int ans = 0; for ( int i = 1; i <= V; i++) if (F[i]) ans++; printf ( "%d\n" , ans); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步