动态规划---背包问题分析

0/1背包

  问题描述

有N件物品和一个容量为V的背包,第i件物品的体积为c[i],价值为w[i]。求将哪些物品放进背包可以使物品价值总和最大(有两种情况:不要求填满背包和填满背包)。

每件商品只有一件,且只能选择放或者不放入背包。

  解决方案

使用动态规划求解,定义一个递归式opt[i][v]表示前i个物品,在背包容量大小为v的情况下,最大的价值。

opt[i][v] = max(opt[i-1][v], opt[i-1][v-c[i]] + w[i])

其中opt[i-1][v]表示第i件物品不装入背包中的总价值,而opt[i-1][v-c[i]]+w[i]表示第i件物品装入背包中的总价值。

通过初始化不同来区别两种情况,第一种情况,不要求填满背包,则:

for i <-0 to Vf[i] <- 0

第二种情况,要求填满背包,则

f[0] <- 0
for i <-1 to Vf[i] <- -65536

    可以理解为,在要求填满背包的情况下,我们只选择上一步的最大价值不小于0的情况,也就是说,在上一步已经满足了填满当时容量的条件,表示从0到V的容量里都填满了物品;而不像不要求填满背包那样,只关心最大价值,而不保证每个容量单位里面都有物品。

    由于每个物品只有1件,所以采用从V向下递减,以此保证每个物品在每次循环过程中只被计算了1遍。

花费的时间复杂度为O(V*T)。

  伪代码

PACKAGE(w, c, V)
#ifdef CANEMPTYfor i <- 0 to Vf[i] <- 0
#elsef[0] <- 0for i <- 1 to Vf[i] <- -65536
#endiffor i <- 0 to nfor v <- V downto c[i]f[v] = max(f[v-c[i]] + w[i], f[v])return f[V]

  代码

#include <iostream.h>using namespace std;
const int V = 100;
const int T = 8;
int f[V+1];
int w[T] = {3, 4, 6, 2, 3, 5, 1, 4};
int c[T] = {15, 25, 20, 10, 30, 20, 5, 15};int package()
{
#ifdef EMPTYf[0] = 0;for(int i = 1; i <= V; i++)f[i] = -65536;
#elsefor(int i = 0; i <= V; i++)f[i] = 0;
#endif    for(int i = 0; i < T; i++){for(int v = V; v > c[i]; v--){f[v] = f[v - c[i]] + w[i] > f[v] ? f[v - c[i]] + w[i]: f[v];}}return f[V];
}
int main(int argc, char *argv[])
{cout<<"The Max Value is "<<package()<<endl;return 0;
}

完全背包问题

  问题描述

有N种物品(数量不限)和一个容量为V的背包,第i件物品的体积为c[i],价值为w[i]。求将哪些物品放进背包可以使物品价值总和最大(有两种情况:不要求填满背包和填满背包)。

  解决方案

动态规划法,推导出递归公式:

f[j] = max(f[j], f[j – w[i]] + v[i])

其中f[j]表示容量为j时的最大价值,f[j-w[i]]+v[i]表示f[j]中包含了第i个物品。

由于每个物品有n件,所以采用从0向上递加,以此保证每个物品在每次循环过程中只被计算了1遍。

同样,两种情况也只是初始化的值不同,同0-1背包问题。

  伪代码

COMPLETE_PACKAGE(w, c, V, N)
#ifdef CANEMPTYfor i <- 0 to Vf[i] <- 0
#elsef[0] <- 0for i <- 1 to Vf[i] <- -65536
#endiffor i <- 0 to Nfor j <- c[i] to V        f[j] = max(f[j], f[j - c[i]] + w[i])return f[V]

  代码

#include <iostream.h>
using namespace std;
const int V = 100;
const int T = 8;
int f[V+1];
int w[T] = { 3,  4,  6,  2,  3,  5, 1,  4};
int c[T] = {15, 25, 20, 10, 30, 20, 5, 15};int complete_package()
{
#ifdef EMPTYfor(int i = 0; i <= V; i++)f[i] = 0;
#elsef[0] = 0;for(int i = 1; i <= V; i++)f[i] = -65536;
#endiffor(int i = 0; i < T; i++)for(int v = c[i]; v <= V; v++)f[v] = (f[v - c[i]] + w[i]) > f[v] ? (f[v - c[i]] + w[i]):f[v];return f[V];
}
int main(int argc, char *argv[])
{cout<<"The Max Value is "<<complete_package()<<endl;return 0;
}

多重背包问题

  问题描述

有N种物品(不定个数)和一个容量为V的背包,第i件物品的体积为c[i],价值为w[i],数量为n[i]。求将哪些物品放进背包可以使物品价值总和最大(有两种情况:不要求填满背包和填满背包)。

  解决方案

可以转换为0-1背包问题。转换方式为,将第i件物品合并成若干种物品,n[i] – 2^k + 1 > 0即k < log(n[i] – 1),取k的最大值,以2^0,2^1…2^(k-1),n[i]-2^k+1为系数,每件合并后的物品的体积和价值都乘以相应的系数组成不同的物品。如:

第i件物品有13件,那么k的最大值为3,系数为1,2,4,6,组成的新物品的体积分别为c[i], 2*c[i],4*c[i]和6*c[i],价值为w[i],2*w[i],4*w[i]和6*w[i]。这样,对所有的物品都进行类似的合并,组成一个新的物品集合,然后利用0-1背包来解决剩下的问题。

    组成新物品系数选定的理由:可以看出,新的系数可以保证在任意组合后,都能获取到0~n[i]个物品的数值,如:n[i]=13,那么我想用其中的10个这样的物品,可以由合并后的系数4和6组成。

  伪代码

Merge_Goods(w, c, n, N)j <- 0for i <- 0 to Np <- 1while p < n[i] + 1nw[j] <- p * w[i]nc[j] <- p * c[i]p <- p * 2j <- j + 1if p / 2 < n[i]nw[j] <- (n[i] - p / 2) * w[i]nc[j] <- (n[i] - p / 2) * c[i]nN = jreturn nN and nw and ncPACKAGE(nw, nc, V, nN)
#ifdef CANEMPTYfor i <- 0 to Vf[i] <- 0
#else    f[0] <- 0for i <- 1 to Vf[i] <- -65536
#endiffor i <- 0 to nNfor v <- V downto nc[i]f[v] <- max(f[v-nc[i]] + nw[i], f[v])return f[V]

  代码

#include <iostream.h>#define MAXNUM 1000
#define EMPTY
int nc[MAXNUM];
int nw[MAXNUM];
int merge_goods(int c[], int w[], int n[], int N)
{int j = 0;for(int i = 0 ; i < N; i++){int p = 1;while(p < n[i] + 1){nc[j] = p * c[i];nw[j] = p * w[i];p = p * 2;j++;}if(p/2 < n[i]){nc[j] = (n[i] - p / 2) * c[i];nw[j] = (n[i] - p / 2) * w[i];j++;}}return j;
}int multi_package(int c[], int w[], int n[], int V, int N)
{int nN = merge_goods(c, w, n, N);int f[V+1];
#ifdef EMPTYfor(int i = 0 ; i <= V; i++)f[i] = 0;
#elsef[0] = 0;for(int i = 1; i <= V; i++)f[i] = -65536;
#endiffor(int i = 0; i < nN; i++){for(int j = V; j >= nc[i]; j--){f[j] = (f[j - nc[i]] + nw[i] > f[j]) ? (f[j - nc[i]] + nw[i]) : f[j];}}return f[V];
}int main(int argc, char *argv[])
{int T = 8;int V = 300;int w[] = { 3,  4,  6,  2,  3,  5, 1,  4};int c[] = {15, 25, 20, 10, 30, 20, 5, 15};    int n[] = { 7, 13,  8,  4, 15, 12, 9, 11};cout<<"Max Value is "<<multi_package(c, w, n, V, T)<<endl;return 0;
}

二维背包问题

    问题描述

一维、二维或者多维是针对于代价来说的,以前讨论的三种背包问题都是在代价为一维的条件下,获取最大价值的,该问题的代价是二维的,即可以理解为背包有体积和承重两种代价限制,分别为VU,获取在这两种代价的上限内所能得到的最大价值。

    解决方案

如果理解了之前的背包问题,该问题的解决办法也就一目了然了,简单的说,就是将之前的f[v]变为f[v][u],将以前的一次循环,变为了两次循环,其它没有理论上的不同了。

如果是0-1背包问题,uv倒序循环;如果是完全背包问题,则uv正序进行循环。

f[i][u][v] = max(f[i-1][u][v] , w[i] + f[i-1][u-a[i]][v-b[i]])

    伪代码(只写出0-1背包,且不要求某个代价为上限值的情况)

 

Two_Package(w, a, b, U, V, N)for i <- 0 to Ufor j <- 0 to Vf[i][j] <- 0for i <- 0 to Nfor u <- U downto a[i]for v <- V downto b[i]f[v][u] = max(f[u-a[i]][v-b[i]]+w[i], f[u][v])return f[u][v]

 

  代码

#include <iostream.h>int two_package(int w[], int a[], int b[], int U, int V, int N)
{int f[U+1][V+1];for(int i = 0; i <= U; i++)for(int j = 0; j <= V; j++)f[i][j] = 0;for(int i = 0; i < N; i++){for(int u = U; u >= a[i]; u--){for(int v = V; v >= b[i]; v--)f[u][v] = (f[u - a[i]][v - b[i]] + w[i] > f[u][v]) ? (f[u - a[i]][v - b[i]] + w[i]):f[u][v];}}return f[U][V];
}int main(int argc, char *argv[])
{const int V = 120;const int U = 140;const int T = 8;int w[T] = { 3,  4,  6,  2,  3,  5,  1,  4};int a[T] = {15, 25, 20, 10, 30, 20,  5, 15};int b[T] = {10, 30, 15, 10, 20, 20, 10, 20};cout<<"Max Value is "<<two_package(w, a, b, U, V, T)<<endl;return 0;
}

分组背包问题

  问题描述

有N种物品和一个容量为V的背包,第i件物品的体积为c[i],价值为w[i]。现将所有物品分成若干组,每组中的物品相互冲突,即在选择时,每组中只能最多选择一件物品,求将哪些物品放进背包可以使物品价值总和最大(有两种情况:不要求填满背包和填满背包)。

  解决方案

可以将k个分组看成k个物品,当做0-1背包问题处理,然后再对每个分组中的单个物品进行选择。

f[k][v] = max(f[k][v], f[k][v-c[k][i]]+w[i])

  伪代码

Group_Package(w, c, K, V, N)for i <- 0 to Vf[i] <- 0for k <- 0 to Kfor v <- V downto 0for i <- 0 to Nif v > c[k][i]f[v] = max(f[v], f[v - c[k][i]] + w[k][i])return f[V]

  代码

#include <iostream.h>const int K = 3;
const int N = 4;int w[K][N] = {{3, 4, 6, 2},{3, 5, 1, 4},{6, 2, 3, 5}
};int c[K][N] = {{15, 25, 20, 10},{20, 15, 30, 20},{30, 30, 20, 5}
};
int group_package(int V)
{int f[V + 1];for(int i = 0; i <= V; i++)f[i] = 0;for(int k = 0; k < K; k++){for(int v = V; v >= 0; v--){for(int i = 0; i < N; i++){if(c[k][i] <= v)f[v] = (f[v - c[k][i]] + w[k][i] > f[v]) ? (f[v - c[k][i]] + w[k][i]) : f[v];}}}return f[V];
}int main(int argc, char *argv[])
{int V = 60;cout<<"Max Value is "<<group_package(V)<<endl;return 0;
}

 

 

 

 

转载于:https://www.cnblogs.com/geekma/archive/2012/11/28/2793355.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463040.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

乱想想关于捕获异常后继续执行的实现。

好像是在csdn上看见的一个问题。 如下 现有A() B() C() 。。。。等很多个方法 但是他担心程序按 try { A(); B();//如这里抛异常 C()将不执行。 C(); //..... } catch (Exception e) …

spring boot 实战

https://windmt.com/2018/04/26/spring-cloud-full-reactive-microservices/ 这篇文章一级棒&#xff0c;实际操作一番&#xff0c;感觉有点理解微服务以及服务发现&#xff0c;服务间调用这几个概念。 但是对于响应式编程以及对于异步非阻塞场景等还是比较头大。 在实际操作中…

MySQL InnoDB的缓冲池之预读失效和缓存池污染

InnoDB的缓存池作用: 缓存表数据和索引数据,把磁盘上的数据加载到缓冲池中,避免每次都进行磁盘IO,起到加速访问的效果. LRU算法(Least recently used): 把入缓存池的页放在LRU的头部,作为最近访问的元素 页在缓冲池中的数据,把它放在队列的前面(情景一)页不在缓冲池中的数据,…

【database】database domain knowledge

Database Principles Database Systems Design Advanced Database Technology 一、Database principles Relational data model – relational algebra SQL – DDL, DML, DCL, ODBC(JDBC) Database design — Entity-Relationship model Relation normal forms XML – DTD, XM…

国内交流电频率和电压的历史渊源

国内交流电频率和电压的历史渊源 发布时间&#xff1a;2009-6-25 14:28 发布者&#xff1a;xiaochunyang 阅读次数&#xff1a;546商用交流电最早的频率是60Hz&#xff0c;电压是110V&#xff0c;其发明者Nikola Tesla是美国人&#xff08;移民&#xff09;并且是受…

Hbase Rowkey设计原则

Hbase是三维有序存储的&#xff0c;通过rowkey&#xff08;行键&#xff09;,column key(column family和qualifier)和TimeStamp(时间戳)这三个维度可以对HBase中的数据进行快速定位。 Hbase中Rowkey可以唯一标识一行记录&#xff0c;在Hbase查询的时候&#xff0c;有以下几种方…

explicit关键字详解

C explicit关键字详解 首先, C中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式). 那么显示声明的构造函数和隐式声明…

Palm应用开发之四Palm 应用模型

本系列目录 Palm Web OS 简介 Palm 应用开发之一开发环境搭建 Palm 应用开发之二从Helloworld开始学习Palm开发Palm应用开发之三appinfo.json文件详解开发语言 应用使用的技术和Ajax使用的技术完全相似&#xff0c;palm webos 系统上建立应用没有专门的语言为其服务&#xff0c…

T-SQL 中ON和WHERE的区别

SQL中ON和WHERE的区别 数据库在通过连接两张或多张表来返回记录时&#xff0c;都会生成一张中间的临时表&#xff0c;然后再将这张临时表返回给用户。在使用left jion时&#xff0c;on和where条件的区别如下&#xff1a;1、 on条件是在生成临时表时使用的条件&#xff0c;它不管…

luogu3830 [SHOI2012]随机树

传送门&#xff1a;洛谷 题目大意&#xff1a;对于一个只有一个节点的二叉树&#xff0c;一次操作随机将这棵树的叶节点的下方增加两个节点。$n-1$次操作后变为$n$个叶节点的二叉树。求&#xff1a;&#xff08;1&#xff09;叶节点平均深度的期望值&#xff08;2&#xff09;树…

Mysql binlog应用场景与原理深度剖析

本文深入介绍Mysql Binlog的应用场景&#xff0c;以及如何与MQ、elasticsearch、redis等组件的保持数据最终一致。最后通过案例深入分析binlog中几乎所有event是如何产生的&#xff0c;作用是什么。 1 基于binlog的主从复制 Mysql 5.0以后&#xff0c;支持通过binary log(二进…

粤语学习--语法

时态篇开篇导言&#xff1a;英语的时态是一种动词形式&#xff0c;不同的时态表示动作行为的不同时间与发生方式。粤语同样也有时态&#xff0c;这种时态是通过动词与对应的前后缀以及时间词共同表示。 &#xff08;一&#xff09;普通时态说明&#xff1a;普通时态一般指经常发…

[BZOJ4349]最小树形图

显然先选每个点都取一遍然后再取满次数最优&#xff0c;用最小树形图决定第一次取的顺序。 朱刘算法的流程是&#xff08;总复杂度O(nm)&#xff09;&#xff1a; 1.对除根外所有点&#xff0c;找到所有指向它的边中权值最小的那一条&#xff0c;记其权值为ind[]。 2.找到所有不…

数据库中间件详解

本文是转载的文章&#xff0c;原文链接&#xff1a;https://mp.weixin.qq.com/s?__bizMzA5MDA5Njk0NQ&mid2456618601&idx1&snc10839f1797e7be1ea41f005b57432df&chksm87897237b0fefb215dd74c28cf5b524984b8f50d2ef13293e37919774f1c51e36642e489ee38&scen…

关于XtraGrid的CustomUnboundColumnData事件的触发条件

要想让非数据绑定的列触发CustomUnboundColumnData事件以便自行处理该列的显示数据&#xff0c;必须至少做到以下几点&#xff1a;1.将该列的UnboundType属性设置为bound(默认值)以外的数据类型2.为该列设置一个窗体内全局唯一的FieldName&#xff0c;注意这个FieldName甚至不能…

读书笔记《集体智慧编程》Chapter 5 : Optimization

本章概要 本章介绍了优化问题的基本概念&#xff0c;以及常见的优化算法&#xff08;随机搜索&#xff0c;爬山&#xff0c;模拟退火&#xff0c;遗传算法&#xff09;。读完本章后&#xff0c;感觉茅塞顿开&#xff0c;之前一直认为遗传算法高深莫测&#xff0c;原来这些算法都…

第五章· MySQL数据类型

一.数据类型介绍二.列属性介绍一.数据类型介绍 1.四种主要类别&#xfffc;1&#xff09;数值类型2&#xff09;字符类型3&#xff09;时间类型4&#xff09;二进制类型 2.数据类型的 ABC 要素1&#xff09;Appropriate&#xff08;适当&#xff09;2&#xff09;Brief&#xf…

MySQL buffer pool里的三种链表和三种page

mysql buffer pool里的三种链表和三种page buffer pool是通过三种list来管理的 1) free list 2) lru list 3) flush list buffer pool中的最小单位是page&#xff0c;在innodb中定义三种page 1) free page :此page未被使用&#xff0c;此种类型page位于free链表中 2) clean pag…

Windows 运行... 可执行的命令

Windows "运行..." 可执行的命令 以下内容与操作系统版本有关&#xff0c;并不保证所有Windows都能运行 winver 检查Windows版本 wmimgmt.msc 打开Windows管理体系结构(wmi) wupdmgr Windows更新程序 wscript Windows脚本宿主设置 write 写字板 winmsd 系统信息 wiaa…

深入浅出Android:初识Intent(BMI)

1、strings.xml 1 <?xml version"1.0" encoding"utf-8"?>2 <resources>3 4 <string name"app_name">BMI</string>5 <string name"height">身高(cm)</string>6 <string …