动态规划之背包问题

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

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

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

说明:

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];
				else
					dp[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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值