Luogu关卡2-15动态规划的背包问题(2017年10月)

Posted zhangwanying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu关卡2-15动态规划的背包问题(2017年10月)相关的知识,希望对你有一定的参考价值。

任务说明:这是最基础的动态规划。不过如果是第一次接触会有些难以理解。加油闯过这个坎。

 

01背包二维数组优化成滚动数组的时候有坑有坑有坑!!!必须要downto,downto,downto

情景和代码见装箱问题。

 

P1060 开心的金明

小明的妈妈给小明N元钱,小明想买m件物品,每个物品价值为 价格*重要度,求出不超过N元钱的情况下,最多能买多少价值的物品,输出价值。

解法:直接的01背包问题,我居然还去看了书。。递推方程一次写不出来。方程需要记忆。

dp[i][j]表示前i件物品总价格不超过j元的最大总价值。

需要学习下怎么在博客园输入latex公式orz。。。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>

using namespace std;


int main() {
    int n, m;
    cin >> n >> m;
    int w[m][2];
    for (int i = 0; i < m; ++i) {
        cin >> w[i][0] >> w[i][1];
        w[i][1] *= w[i][0];
    }

    int dp[m+1][n+1];
    memset(dp, 0, sizeof(dp));

    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (w[i-1][0] > j) { dp[i][j] = dp[i-1][j]; }
            else {
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1][0]] + w[i-1][1]);
            }
        }
    }
    cout << dp[m][n] << endl;

    return 0;
}
View Code

 

P1164 小A点菜

有M元, N种菜(每个菜只有一份),每种菜有价格,求能把M元全花完的方案数。

解答:一开始全WA....哭死..其实还是经典的01背包问题。

一维的转移方程为: dp[j] += dp[j-price[i-1]]; 初始化条件为 dp[0] = 1, dp[1..m] = 0。 (因为需要花0元只有一种方案,就是啥也不买)

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main() {
 5     int n, m;
 6     cin >> n >> m;
 7     int dp[m+1] = {0};
 8     dp[0] = 1;
 9     int price[n];
10     for (int i = 0; i < n; ++i) {
11         cin >> price[i];
12     }
13     for(int i = 1; i <= n; ++i) {
14         for (int j = m; j >= 0; --j) {
15             if (j >= price[i-1]) {
16                 dp[j] = dp[j] + dp[j-price[i-1]];
17             }
18         }
19     }
20     cout << dp[m] << endl;
21     return 0;
22 }
View Code

 

 

 

金明的预算方案

 

 

 

P1048 采药

就是01背包,裸的,直接写了,方程同P1060

提交一次AC

 1 #include <cstdlib>
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 int main() {
 8     int T, M;
 9     cin >> T >> M;
10     int w[M][2];
11     for (int i = 0; i < M; ++i) {
12         cin >> w[i][0] >> w[i][1];
13     }
14     int dp[M+1][T+1];
15     memset(dp, 0, sizeof(dp));
16 
17     for (int i = 1; i <= M; ++i) {
18         for (int j = 1; j <= T; ++j) {
19             if (j < w[i-1][0]) { dp[i][j] = dp[i-1][j]; }
20             else {
21                 dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1][0]] + w[i-1][1]);
22             }
23         }
24     }
25     cout << dp[M][T] << endl;
26     return 0;
27 }
View Code

 

P1049 装箱问题

有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30,每个物品有一个体积(正整数)。 要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

就是求怎么样是用的空间最大。裸的01背包。优化成滚动数组的时候被坑了。

//写成滚动数组的时候,max(dp[j], dp[j-w[i-1]]+w[i-1]);如果是从左到右,那么dp[j-w[i-1]]是个已经被更新过的值。。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 
 6 using namespace std;
 7 
 8 int main() {
 9     int c, n;
10     cin >> c >> n;
11     int w[n+1];
12     for (int i = 0; i < n; ++i) {
13         cin >> w[i];
14     }
15     int dp[c+1] = {0};
16     for (int i = 1; i <= n; ++i) {
17         //滚动数组这么写的时候,max(dp[j], dp[j-w[i-1]]+w[i-1]);如果是从左到右,那么dp[j-w[i-1]]是个已经被更新过的值。。
18         //for (int j = 1; j <= c; ++j) {
19         for (int j = c; j >= 1 ; --j) {
20             if (j < w[i-1]) { dp[j] = dp[j]; }
21             else {
22                 dp[j] = max(dp[j], dp[j-w[i-1]]+w[i-1]);
23             }
24         }
25     }
26     cout << c - dp[c] << endl;
27     return 0;
28 }
View Code

 

P1616 疯狂的采药

采药问题的升级版,不限制每种物品的个数。完全背包问题(每个物品无穷个)。

完全背包的解法就是01背包的downto的写法改成正着写...不过这不是重点。重点是理解为啥需要正着写。

提交一次AC了

 

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main() {
 6     int T, M;
 7     cin >> T >> M;
 8     int w[M][2];
 9     for (int i = 0; i < M; ++i) {
10         cin >> w[i][0] >> w[i][1];
11     }
12     int dp[T+1] = {0};
13     for (int i = 1; i <= M; ++i) {
14         for (int j = 1; j <= T; ++j) {
15             if (j < w[i-1][0]) { continue; }
16             else {
17                 dp[j] = max(dp[j], dp[j-w[i-1][0]]+w[i-1][1]);
18             }
19         }
20     }
21     cout << dp[T] << endl;
22     return 0;
23 }
View Code

 

以上是关于Luogu关卡2-15动态规划的背包问题(2017年10月)的主要内容,如果未能解决你的问题,请参考以下文章

动态规划-背包问题

动态规划的引入 P1048 采药01背包

动态规划的引入 P1616 疯狂的采药完全背包

动态规划的引入 P1802 5倍经验日变形的01背包

Luogu2737 USACO4.1麦香牛块(动态规划)

2019.10.18luogu TG5动态规划进阶