完全背包问题

01背包问题和完全背包问题 01背包 01背包字面意思来看0就是不拿,1就是拿,且每次只能拿一个物品放入背包。 开二维数组的状态方程: 此情景为往固定容量的背包里装物品,使包内物品为最大价值 实际上就是在每个物品的基础上,遍历所有可能的背包空间,如果放得下去就比较放与不放对价值的影响 一维数组的状态方程: ... 阅读详情

完全背包问题的特点是每种物品数量没有限制,可以无限使用。很容易定义完全背包状态转移方程,根据第i件物品进行划分进行决策。设第i个物品选择k个,于是:

            W[i,j]=max{ W[i -1,j - k*v[ i ] ]+k*p[i] }   (0<= k<=j / v[i] ),k=0时即表示不用选择的情况。此时对于每一个状态i,我们要考虑(1+2+..V)/v[i]次。当v[i]比较小时,光考虑第i个状态时间复杂度就接近O(V^2),总时间复杂度接近O(NV^2).当然还可以对其做一些改进。为了方便操作,将价格和体积捆绑为一个结构体Goods,两个属性是p和v。状态转移方程可以写为:

            W[i,j]=max{ W[i -1,j - k*goods[i].v+k*goods[i].p }   (0<= k<=j / v[i] ) .

      对于不要求背包装满的情况,首先可以做一些简单的优化,对于第i个物品和第j个物品,若满足 v[i]<=v[j]且p[i]>=p[j]时,我们完全可以不考虑第j个物品,这是由于物品i相对于物品j来说是物美价廉。我们可以用桶排序方法来完成优化。建立bucket[1...V],超过体积V的物品直接删除。当没有体积为 i 的物品时,bucket[i]设置为空。当有多个体积为i的物品时,bucket[i]中放体积为i但是价格最大的那个物品。然后扫描一次桶,若i<j但是bucket[i].p>=bucket[j].p则将bucket[j]设置为空(删掉)。总的过程时间为o(V).,空间也为O(V).但是对于要求将背包装满的情况则不能这样优化,否则本来有解也可能导致无解。当然这些优化并不能改变最坏情况下的复杂度。下面一种思想将完全背包问题转变为01背包问题,对于第 i 个物品,最多有k=V/v[i]个.从而我们可以将第i个物品分解为k个一样的物品。这样问题就转化为了01背包问题,然而时间复杂度没变。另一个改进是采用二进制的思想:将第i个物品质分解为体积:v[i] , 2*v[i],v[i]*2^2...v[i]*2^log(V/v[i]),相应价值也类似递增,这是由于二进制可以表示任意数。这样得到了一个不错的优化结果,第i个物品分解为log(V/v[i])+1个,第 i 个状态转移次数大约为(log(V/v[i])+1)*V,当v[i]比较小时,此式子接近O(VlogV),于是总的时间度接近O(NVlogV),已经得到了一个很大的改进。以下代码是不要背包求装满的情况,开始部分利用桶排序原则删除了一些物品,然后将物品分解转变为二进制。

<span style="font-size:10px;">/*不要求背包装满*/</span>
<span style="font-size:10px;">#include<iostream>
using namespace std;
#define MAX_SIZE 500
int N, V;
struct Goods{
	int p, v;
};
Goods goods[MAX_SIZE];
Goods bucket[MAX_SIZE];
bool flag[MAX_SIZE];
int W[MAX_SIZE];
int main(){
	int i, j,pos,nowPrice,ans,total;
	Goods temp;
	memset(flag, 0, sizeof(flag));
	cin >> N >> V;
	for (i = 1; i <=N; i++)
		cin >> goods[i].v >> goods[i].p;
	//-------------------------------------------------------------------------
	for (i = 1; i <=N; i++){
		if (goods[i].v>V)
			continue;
		else  if (!flag[goods[i].v] || goods[i].p>bucket[goods[i].v].p){
			flag[goods[i].v] = 1;
			bucket[goods[i].v] = goods[i];
		}
	}
	pos =1,ans=1;
	while (!flag[pos])
		pos++;
	nowPrice = bucket[pos].p;
	goods[ans++] = bucket[pos];
	for (i = pos + 1; i <=V; i++){
		if (flag[i] && nowPrice < bucket[i].p){
			nowPrice = bucket[i].p;
			goods[ans++] = bucket[i];
		}
	}

	/*--------------------------------------------------------------以上是优化过程代码*/
	pos = ans;
	for (i = 1; i < ans; i++){
		temp = goods[i];</span>
<span style="font-size:10px;">                total=temp.v;
		while(total<V){
			temp.v *= 2;
			temp.p *= 2;
			goods[pos++] = temp;</span>
<span style="font-size:10px;">                        total+=temp.v;
		}
	}
	/*--------------------------以上完成拆分,如今已有pos个物品,下面利用01背包解法*/
	memset(W, 0, sizeof(W));
	for (i = 1; i <= pos; i++){
		for (j = V; j >= goods[i].v; j--)
		if (W[j]< W[j - goods[i].v] + goods[i].p)
			W[j] = W[j - goods[i].v] + goods[i].p;
	}
	cout << W[V] << endl;
	return 0;
}</span>

在要求背包装满的情况下,就不得做删除的优化了。HDU1004就是一个要求背包装满的问题。下面是HDU1004:

Problem Description
Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action comes from Irreversibly Bound Money (IBM). The idea behind is simple. Whenever some ACM member has any small money, he takes all the coins and throws them into a piggy-bank. You know that this process is irreversible, the coins cannot be removed without breaking the pig. After a sufficiently long time, there should be enough cash in the piggy-bank to pay everything that needs to be paid. 

But there is a big problem with piggy-banks. It is not possible to determine how much money is inside. So we might break the pig into pieces only to find out that there is not enough money. Clearly, we want to avoid this unpleasant situation. The only possibility is to weigh the piggy-bank and try to guess how many coins are inside. Assume that we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency. Then there is some minimum amount of money in the piggy-bank that we can guarantee. Your task is to find out this worst case and determine the minimum amount of cash inside the piggy-bank. We need your help. No more prematurely broken pigs! 
 

Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing two integers E and F. They indicate the weight of an empty pig and of the pig filled with coins. Both weights are given in grams. No pig will weigh more than 10 kg, that means 1 <= E <= F <= 10000. On the second line of each test case, there is an integer number N (1 <= N <= 500) that gives the number of various coins used in the given currency. Following this are exactly N lines, each specifying one coin type. These lines contain two integers each, Pand W (1 <= P <= 50000, 1 <= W <=10000). P is the value of the coin in monetary units, W is it's weight in grams. 
 

Output
Print exactly one line of output for each test case. The line must contain the sentence "The minimum amount of money in the piggy-bank is X." where X is the minimum amount of money that can be achieved using coins with the given total weight. If the weight cannot be reached exactly, print a line "This is impossible.". 
 

Sample Input
3 10 110 2 1 1 30 50 10 110 2 1 1 50 30 1 6 2 10 3 20 4
 

Sample Output
The minimum amount of money in the piggy-bank is 60. The minimum amount of money in the piggy-bank is 100. This is impossible.
 
这是一个要求典型的要求背包装满的完全背包问题。直接给出二进制分解后的AC代码:
<span style="font-size:10px;">#include<iostream>
using namespace std;
#define MAX_SIZE 10002
int N, V;
struct Goods{
	int p, v;
};
Goods goods[MAX_SIZE];
int W[MAX_SIZE];
int main(){
	int i, j,pos,ans,E,F,T,total;
	Goods temp;
	cin >> T;
	while (T--){
		memset(W, -1, sizeof(W));
		W[0] = 0;
		cin >> E >> F;
		V = F - E;
		cin >> N;
		for (i = 1; i <= N; i++)
			cin >>goods[i].p>>goods[i].v;
		ans = N + 1;
		for (i = 1; i <=N; i++){
			temp = goods[i];
			total = temp.v;
			while (total <V){
				temp.v *= 2;
				temp.p *= 2;
				goods[ans++] = temp;
				total += temp.v;
			}
		}
		for (i = 1; i <ans; i++){
			for (j = V; j >= goods[i].v; j--){
				pos = j - goods[i].v;
				if (W[pos] != -1 && (W[j] == -1 || W[pos] + goods[i].p < W[j]))
					W[j] = W[pos] + goods[i].p;
			}
		}
		if (W[V] != -1)
			cout << "The minimum amount of money in the piggy-bank is " << W[V] << '.' << endl;
		else
			cout << "This is impossible." << endl;
	}
	return 0;
}</span>

二进制分解基于思想是将完全背包问题转化为01背包问题。但是这种方法也不是完全背包最快的办法,最后还有时间复杂度为O(NV)的算法。进一步改进,并让 j 枚举 0..V的情况,有O(VN)的算法。改进后状态转移方程为:
                    W[ j ]=MAX{W[ j ],W[ j-v[ i] ] +p[ i ]};
在01背包问题中,我们只关心第i中物品选还是不选。而完全背包是每件物品最多可选V/v[i]件。所以在考虑加选一种第i中物品时前面在子结果W[ i,j-v[i]]中可能已经选过第i件物品。即是要采用 for j=v[i] to V的循环,同样的求解HDU 1114 时,使用时间比二进制方法快很多:
<span style="font-size:10px;">#include<iostream>
using namespace std;
#define MAX_SIZE 10002
int N, V;
struct Goods{
	int p, v;
};
Goods goods[MAX_SIZE];
int W[MAX_SIZE];
int main(){
	int i, j,pos,E,F,T;
	cin >> T;
	while (T--){
		memset(W, -1, sizeof(W));
		W[0] = 0;
		cin >> E >> F;
		V = F - E;
		cin >> N;
		for (i = 1; i <= N; i++)
			cin >>goods[i].p>>goods[i].v;
		for (i = 1; i <=N; i++){
			for (j = goods[i].v; j <= V; j++){
				pos = j-goods[i].v;
				if (W[pos] != -1 && (W[j] == -1 || W[pos] + goods[i].p < W[j]))
					W[j] = W[pos] + goods[i].p;
			}
		}
		if (W[V] != -1)
			cout << "The minimum amount of money in the piggy-bank is " << W[V] << '.' << endl;
		else
			cout << "This is impossible." << endl;
	}
	return 0;
}</span>



实战测评:4大搜索API(You.com/Tavily/Exa/Perplexity)谁更适合你的AI项目?附Python调用代码 本文实战测评了You.com、Tavily、Exa和Perplexity四大搜索API在AI项目中的集成应用,详细对比了它们的技术特性和Python调用方法。针对LLM实时数据需求,You.com的优化设计表现突出,支持32k大上下文窗口和快速响应。文章提供了完整的代码示例和场景化选型建议,帮助开发者高效集成搜索API到AI项目中。 阅读详情

相关推荐

卡尔曼滤波与目标追踪

卡尔曼滤波与目标追踪为什么要学卡尔曼滤波?卡尔曼滤波是什么?一些概率论的知识基础卡尔曼滤波完整推导状态估计计算卡尔曼增益预测和更新 卡尔曼滤波部分我打算分三节(三次博客的内容): 卡尔曼滤波与行人状态估计 扩展卡尔曼滤波(EKF)与传感器融合 过程模型,无损卡尔曼滤波(UKF)与车辆状态轨迹 为什么要学卡尔曼滤波? 卡尔曼滤波以及其扩展算法能够应用于目标状态估计,如果这个目标是行人,那么就是行人状态估计(或者说行人追踪),如果这个目标是自身,那么就是车辆自身的追踪(结合一些地图的先验,GPS等数据的话就

qq_43232556的博客 4174

完全背包理论基础

因为dp[j] 是根据 下标j之前所对应的dp[j]计算出来的。只要保证下标j之前的dp[j]都是经过计算的就可以了。有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i]。我们知道01背包内嵌的循环是从大到小遍历,为了保证每个物品仅被添加一次。,求解将哪些物品装入背包里物品价值总和最大。

qq_63953838的博客 147

ego-planner启动参数深度解析:从配置到实战避障应用

本文深入解析EGO-Planner启动参数的配置与实战应用,重点探讨无人机自主导航中的避障性能优化。通过环境感知、运动约束和算法控制三类参数的详细说明,结合ROS和RViz工具,提供从基础配置到高级调优的完整指南,帮助开发者提升无人机在复杂场景下的规划效率和安全性。

rum55的博客 246

【动态规划】背包问题 {01背包问题;完全背包问题;二维费用背包问题}

【动态规划】背包问题 {01背包问题;完全背包问题;二维费用背包问题}

52Herzt的博客 5527

WSL2+Ubuntu20.04纯root环境搭建指南:告别权限烦恼的终极方案

本文提供了一份详细的WSL2+Ubuntu20.04纯root环境搭建指南,旨在为本地开发与学习打造一个免去权限干扰、极致流畅的Linux子系统环境。通过启用WSL2、安装Ubuntu 20.04,并执行核心的root用户设置,开发者可以彻底告别频繁的sudo操作,提升在文件操作、容器调试和系统配置等方面的效率。

time3的博客 474

Android perfetto 简介

android linux 性能优化 原理及操作

求变,从思想开始 3480

【算法】一文带你搞懂完全背包!(附背包问题总结)

详解动态规划中的完全背包问题原理及应用,了解多重背包,以及总结笔试面试中解决背包问题的关键。

Conner7的博客 7444

基于若依的ruoyi-nbcio-plus支持VForm3表单字段数据保存到数据库的一种方法——全网首创(一)

基于若依的ruoyi-nbcio-plus支持VForm3表单字段数据保存到数据库的一种方法——全网首创(一)

宁波阿成的博客 660

完全背包问题(动态规划(DP))

原题 完全背包问题 有n种重量和价值分别为wi,vi的物品。从这些物品中挑选总重量不超过W的物品,求出挑选物品价值总和的最大值。在这里,每种物品可以挑选任意多件。 1 1 1 样例输入 n=3 (w,v)={(3,4),(4,5),(2,3)} W=7 样例输出 10(0号物品选1个,2号物品选2个) 涉及知识及算法 递推关

快速进入竞赛模式! 7554

SAR成像概述

1. 发展概述 雷达是英文Radar(Radio detection and ranging)的音译,原意为“无线电探测与测距”。雷达的发明是无线电发展史上的里程碑,二战时,英国急需通过雷达探测空中金属物体来帮助搜寻德国飞机,这期间,雷达技术飞速发展,发展出了地对空、空对地轰炸、空对空火控、敌我识别等功能。雷达在第二次世界大战中发挥了重大作用,至今仍是军用和许多民用领域的重要传感器。 早期雷达系统通过时间延迟来测距,通过天线指向来测角,通过多普勒频移测速。1951年,Carl Wiley发现,通..

5075

Python控制程控电源(USB)

随着智能电动汽车行业的持续发展,汽车电子或嵌入式设备在软硬件的测试中,都会使用程控电源供电,特别是自动化测试、压力测试场景必定使用到程控电源控制,控制电源上下电,监听电源电流、电压等,以下就以常见的艾德克斯程控电源为例,分享如何通过USB连接方式Python语言来控制程控电源。

测试领域技术分享 2867

DP:完全背包问题

在完全背包问题中,每种物品有无限个可用,目标是在限定的背包容量内,选择物品使得总价值最大。动态规划通过将问题分解为子问题,利用子问题的解来构建最终解。完全背包问题具有最优子结构性质和重复子问题结构,非常适合用动态规划求解。通过对完全背包问题的深入探讨,我们了解了动态规划在解决这类问题中的重要性。完全背包问题在实际应用中非常广泛,例如货币兑换、资源分配和路径规划等。在解决过程中,我们学会了如何定义状态、确定状态转移方程,并通过优化空间复杂度提升算法效率。

2301_79969994的博客 1646

NX二次开发PK获取对象类型

PK_ENTITY_ask_class(),获取对象类型建议用这个函数,比较通用,包含所有对象类型,可以替代UF_MODL_ask_edge_type(),UF_MODL_ask_body_type(),UF_MODL_ask_face_type()等函数。

qq_39541524的博客 827

【动态规划】完全背包问题应用

【动态规划】完全背包问题应用

fight_p的博客 3065

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

完全背包问题(动态规划)

完全背包问题 题目: 有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用。第 i 种物品的费用是 c[i],价值是 w[i] 。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 一、验证动态规划求解的可行性 这个问题可以不可以像01背包问题一样使用动态规划来求解呢?来证明一下即可。 首先,先用反证法证明最优化原理: 假设完全背包...

但行好事,莫问前程 6143

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

动态规划——完全背包问题

聪明人都会点进来学习!!动态规划看这一篇就够了!!!本文详细讲解了动态规划的核心思路(配有图片),还以经典问题——完全背包问题为例,先从基础解法开始讲解思路,再一步步优化(一维数组),带有完整代码(有详细注释),对于难以理解的地方还会举例讲解,还会和01背包问题对比思考,赶紧点进来学习吧!!!

yourgrandfather_的博客 3947

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

九大背包问题专题--完全背包问题(详解,最优解)

2.完全背包问题 和01背包问题的区别: 01背包1件物品只能选或者不选 完全背包问题:1件物品可以重复选多次,只要不超过总体积 题目: 问题: 有N件物品和一个容量是V的背包。 第i件物品的体积是vi,价值是wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包的容量,且价值最大。 输入格式 第一行有两个整数,N,V用空格隔开,分别表示物品数量和背包容积。 接下来有N行,每行两个整数vi...

gl620321的博客 1万+

01背包问题&&完全背包问题

01背包问题 问题描述:有N件物品,每件物品的重量为w[i],价值为c[i],现有一个容量为V的背包,问如何选取物品放入背包中,使得物品的总价值最大。其中每种物品都只有1件。 输入: 5 8 //物品数 最大容量 3 4 //每件物品的重量 每件物品的价值 5 5 1 2 2 1 2 3 输出:10 完全背包问题 问题描述:有N件物品,每件物品的重量为w[i],价值...

jelly的博客 1798

背包问题/完全背包问题全解

核心代码 2:res[i][j] = Math.max(res[i-1][j],res[i-1][j-w[i]]+v[i]) 比较上一步(i-1)的最优方案,和这一步的最优方案谁的钱最多。k++) 就是可以加个w[i]物品,思想差不多,k 一开始是取0的意思是让res[i][j]进入else循环,得出res[i][j] = res[i][j-1](至少先继承一下前辈,如果k=1时不满足循环条件会没有数据),其他要注意的就是前面说的核心代码要注意乘以k的倍数。本人水平欠佳,望多多大佬指点!

qq_62691586的博客 675
上一篇: 01背包问题
下一篇: 第二讲 数据库系统结构抽象
Tander_Tang
博客等级 码龄11年 7粉丝 49原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值