动态规划之背包问题

来源:互联网 发布:全国姓名数据库 编辑:程序博客网 时间:2024/05/22 11:42

最近刷题遇到好几道背包问题,背包问题是动态规则中的一类体型,在考察算法的笔试中经常遇到。

关于背包问题,文章 背包问题九讲 中已经做了很多分析,这里就不再细述,建议好好看看这篇文章。

然而文章给了许多案例分析,却没有很好的练习。

说明:

1、本文目的不在于讲解背包问题的分析与讲解,而是收集了一些背包问题。希望学习者学习背包问题的时候能找到一些对应的题加以练习。

2、本文根据我是刷题中遇到的背包问题,会不定期更新内容。


0-1 背包问题

1、兑换奖券

http://hihocoder.com/problemset/problem/1038?sid=842443

基本解法:

#include <iostream>#include <algorithm>#include <vector>using namespace std;int main(){int i, j, n, m, need, val;while (cin >> n >> m){vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));for (i = 1; i <= n; ++i){cin >> need >> val;for (j = 0; j <= m; ++j){if(j<need)dp[i][j] = dp[i - 1][j];elsedp[i][j] = max(dp[i - 1][j], dp[i - 1][j - need] + val);}}cout << dp[n][m] << endl;}return 0;}


空间优化:

#include <iostream>#include <algorithm>#include <vector>using namespace std;int main(){int i, j, n, m, need, val;while (cin >> n >> m){vector<int> dp(m + 1, 0);for (i = 0; i < n; ++i){cin >> need >> val;for (j = m; j >= need; --j)dp[j] = max(dp[j], dp[j - need] + val);}cout << dp[m] << endl;}return 0;}

如果要输出最优方案,增加一个state状态数组,修改代码如下:

#include <iostream>#include <algorithm>#include <vector>using namespace std;int main(){int i, j, n, m, need, val;while (cin >> n >> m){vector<int> dp(m + 1, 0), needs(n), vals(n);vector<vector<int>> state(n, vector<int>(m + 1, 0));for (i = 0; i < n; ++i){cin >> need >> val;needs[i] = need;vals[i] = val;for (j = m; j >= need; --j){if (dp[j] < dp[j - need] + val){dp[j] = dp[j - need] + val;state[i][j] = 1;}}}cout << dp[m] << endl;i = n;j = m;while (--i >= 0){if (state[i][j] == 1){cout << needs[i] << " ";j -= vals[i];}}}return 0;}


2、和为M的组合的个数(求方案数)

https://nanti.jisuanke.com/t/310

在N个数中找出其和为M的若干个数。先读入正整数N(1< N< 100)和M(1< M< 10000),  再读入N个正数(可以有相同的数字,每个数字均在1000以内),  在这N个数中找出若干个数,  使它们的和是M,  把满足条件的数字组合都找出来以统计组合的个数,输出组合的个数(不考虑组合是否相同)

#include <iostream>#include <vector>using namespace std;int main(){int n, m, coin;cin >> n >> m;vector<int> dp(m + 1, 0);dp[0] = 1;for (int i = 1; i <= n; ++i){cin >> coin;for (int j = m; j >=coin; --j)dp[j] += dp[j - coin];}cout << dp[m] << endl;return 0;}



完全背包问题

1、兑换奖券

http://hihocoder.com/problemset/problem/1043?sid=842590

#include <iostream>#include <algorithm>#include <vector>using namespace std;int main(){int i, j, n, m, need, val;while (cin >> n >> m){vector<int> dp(m + 1, 0);for (i = 0; i < n; ++i){cin >> need >> val;for (int j = need; j <= m; ++j)dp[j] = max(dp[j], dp[j - need] + val);}cout << dp[m] << endl;}return 0;}


2、换零钱(求方案数)

http://www.nowcoder.com/practice/185dc37412de446bbfff6bd21e4356ec

有一个数组changes,changes中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,对于一个给定值x,计算组成这个值的方案数。

int countWays(vector<int> changes, int n, int x)    {        int coin;        vector<int> dp(x + 1, 0);        dp[0] = 1;        for (int i = 0; i < n; ++i)        {            coin=changes[i];            for (int j = coin; j <=x; ++j)                dp[j] += dp[j - coin];        }        return dp[x];    }

3、换零钱(求最少硬币数)

https://leetcode.com/problems/coin-change/

题解 http://blog.csdn.net/zmq570235977/article/details/51694860


分组背包问题

不超过N元钱:https://nanti.jisuanke.com/t/256

题解:http://blog.csdn.net/zmq570235977/article/details/52354503



泛化物品

提升英雄: http://hihocoder.com/problemset/problem/1091

题解:http://blog.csdn.net/zmq570235977/article/details/52151096


0 0
原创粉丝点击