简单01背包 完全背包

01背包问题

有n个重量和价值分别为Wi,Vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。

1<=N<=100

1<=Wi,Vi<=100

1<=W<=10000

第一行输入n的值

接下来n行输入Wi,Vi

最后一行输入W

For example:

Input:

4

2 3

1 2

3 4

2 2

5

Output:

7

在解决01背包问题,我们将N件物品拆分成N步,每次从N件物品中拿出一件,并于0~W重量中的最优价值进行比较(前提是那件物品能够放的下)。
所以我们需要一个辅助的dp[j]数组,j表示剩余空间的量。
初始dp数组值为0(因为没有物品放入价值当然为0)

求n件物品在重量在W内的最大价值,我们就必须求出:

1件物品在重量为1的最优价值;1件物品在重量为2的最优价值...1件物品在重量为W的最优价值。

1件物品在重量为1的最优价值;1件物品在重量为2的最优价值...1件物品在重量为W的最优价值。
当j<w[i],也就是物品放不下的时候保持原来的价值
当j>=w[i]时,我们就要比较原数值与“腾出”来w[i]单位的价值+该物品的价值。选择较大的值进行覆盖。(因为可能会用到j之前的数值,所以j必须从高位向低位移动)
公式:dp[j] = max(dp[j], dp[j - w[i]] + v[i])   (j >= w[i])
最后dp[W]就是解得值。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
void solve(int dp[], int n, int weight, int w[], int v[]);
int main()
{
	int n, w[101], v[101], dp[101], i, j, W;
	while (~scanf("%d", &n))
	{
		for (i = 0; i<n; i++)
			scanf("%d %d", &w[i], &v[i]);
		scanf("%d", &W);
		memset(dp, 0, sizeof(dp));
		solve(dp, n, W, w, v);
		printf("%d\n", dp[W]);
	}
	return 0;
}
void solve(int dp[], int n, int W, int w[], int v[])
{
	for (int i = n - 1; i >= 0; i--)
		for (int j = W; j >= w[i]; j--)		//逆序填表
			dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}

完全背包

有n种重量和价值分别为Wi,Vi的物品。从这些物品中挑选总重量不超过W的物品,求出挑选物品价值总和的最大值。在这里,每种物品可以挑选任意多件。

For example:

Input:

3

3 4

4 5

2 3

7

Output:

10

完全背包与01背包解题思路一样,只不过在是否重复放第i件物品时,与j-w[i]的机制一样,所以放与不放取决于dp[j-w[i]]的值,所以填表顺序必须正序填充。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
void solve(int dp[101], int w[], int v[], int n, int W);
int main()
{
	int w[101] = { 0 }, v[101] = { 0 }, dp[101] = { 0 }, n, i, W;
	while (~scanf("%d", &n))
	{
		for (i = 0; i<n; i++)
			scanf("%d %d", &w[i], &v[i]);
		scanf("%d", &W);
		solve(dp, w, v, n, W);
		printf("%d\n", dp[W]);
		memset(dp, 0, sizeof(dp));
		memset(w, 0, sizeof(w));
		memset(v, 0, sizeof(v));
	}
	return 0;
}
void solve(int dp[101], int w[], int v[], int n, int W)
{
	for (int i = n - 1; i >= 0; i--)
		for (int j = 1; j <= W; j++)	//正序填表
			if (j >= w[i])
				dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值