背包问题-01背包-P1049 装箱问题

01背包

P1049 装箱问题

P1049 装箱问题

f[i][j]: 把前面 i 件物品放进容量为 j 的背包当中所获得的最大价值
现在有 n 件物品,背包容积为 V
那么列出状态转移方程:
f[i][j]
= max(f[i-1][j], f[i-1][j-v[i]] + w[i]) , j > v[i]
= f[i-1][j] , j <= v[i]
= 0 , i = 0 or j = 0 //全局数组创建的时候默认为 0,可省略
其实就是对任意一个物品 i 而言,要不要放进背包的问题,如果不要,最大价值是 f[i-1][j],否则,可以创造f[i-1][j-v[i]] + w[i] 的最大价值

#include<bits/stdc++.h>//万能头文件
using namespace std;
#define maxn 20005
int f[maxn][maxn], 
	s[maxn],      //时间, 即空间 space 
	v[maxn];      //价值 value

int main()
{
	int V, n, i, j;
	scanf("%d%d",&V,&n);
	for(i = 1; i <= n; i++)
	{
		scanf("%d",&v[i]);
		s[i] = v[i];
	}
	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= V; j++)
		{
			f[i][j] = f[i-1][j];//如果放不下物品 i 
			if(s[i] <= j)
			{
				f[i][j] = max(f[i-1][j-s[i]]+v[i], f[i-1][j]);
			}
		}
	}
	printf("%d", V - f[n][V]);
	return 0;
}

主要是把一般的二维转化成一维度的问题。
我想到有2种方式:
(1):令f[j] = f[n-1][j], 之前有 f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i]) , j > v[i],因为f[i][j] >= f[i-1][j],可以多选择一个物品时的最大价值一定不会低,那么 f[j] = f[n-1][j] >= f[i-1][j] , n >= i ,好了原式可化为
f[j] = max(f[j], f[j-v[i]] + w[i])
还要注意一点,要反着算,因为这样的话,在推 f[p] 的时候就有 f[p-v[i]] = f[i-1][p-v[i]],算到这一层(i)的时候 i = 0, 1, … i-1 已经跑完了,不错的,f[p-v[i]]刚好存储了我想要的数据,要是还按照原来的顺序的话,这个时候 f[p-v[i]] 就已经被更新过了,是f[i][p-v[i]] 不是我们需要的,错误。

(2):用人话来说原来的状态转移方程是在考虑要不要放物品 i 的问题,也就是说,和上面一个状态在比较,假如把第一维去掉,是没有影响的(i、i-1 就代表了当前状态和上一个状态,数组的历史数组自然存储了下来)(这是某位大佬同学告诉我的,偷偷告诉你,他高中就学会了)

#include<bits/stdc++.h>//万能头文件
using namespace std;
#define N 1000000
int v[105], s[105]; 
//v[i]: 第i件物品的价值, s[i]:第i件物品的体积
//这里价值即为体积
int f[N];//只需要一维数组就好了 f[j] = f[n-1][j]  

int main()
{
	int i, j;
	int V, n; // n件物品,背包容量 V 
	scanf("%d%d", &V, &n);
	for(i = 1; i <= n; i++)
	{
		scanf("%d", &s[i]);
	}
	for(i = 1; i <= n; i++)
	{
		for(j = V; j >= s[i]; j--)//反着来 
		{
			f[j] = max(f[j], f[j-s[i]]+s[i]);
		}
	}
	printf("%d", V-f[V]);  
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值