完全背包

2.1 题目

有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用。放入第 i 种物品
的费用是 C i ,价值是 W i 。求解:将哪些物品装入背包,可使这些物品的耗费的费用总
和不超过背包容量,且价值总和最大。

2.2 基本思路

这个问题非常类似于 01 背包问题,所不同的是每种物品有无限件。也就是从每种
物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取 0 件、取 1 件、取 2
件......直至取 ⌊V /C i ⌋ 件等许多种。
  如果仍然按照解 01 背包时的思路,令 F [i, v] 表示前 i 种物品恰放入一个容量为 v
的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:

F [i, v] = max{F [i − 1, v − kCi ] + kWi | 0 ≤ kCi ≤ v}

寒冰王座

#include <cstdio>
#include<algorithm>
#include<string.h>
#define Max(a,b) a>b?a:b
using namespace std;
int main()
{
    int t;
    int dp[4][10010],val[4]={0,150,200,350},vom[4]={0,150,200,350};
    scanf("%d",&t);
  while(t--)
  {
        int v;
        scanf("%d",&v);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=3;i++)
        {
            for(int j=0;j<=v;j++)//v必须升序
            {
                for(int k=v/vom[i];k>=0;k--)//k必须降序
                {
                    if(j-k*vom[i]>=0)
                    dp[i][j]=Max(dp[i-1][j],dp[i][j-k*vom[i]]+k*val[i]);
                    else dp[i][j]=dp[i-1][j];
                }
            }
        }
        printf("%d\n",v-dp[3][v]);
  }
}

这跟 01 背包问题一样有 O(VN ) 个状态需要求解,但求解每个状态的时间已经不
是常数了,求解状态 F [i, v] 的时间是 O( C Vi ) ,总的复杂度可以认为是 O(NV ΣV/Ci ) ,是
比较大的。
  将 01 背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明 01 背包
问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是要试图改进这个
复杂度。

2.4 转化为 01 背包问题求解

01 背包问题是最基本的背包问题,我们可以考虑把完全背包问题转化为 01 背包问
题来解。
  最简单的想法是,考虑到第 i 种物品最多选 ⌊V /Ci ⌋ 件,于是可以把第 i 种物品转
化为 ⌊V /Ci ⌋ 件费用及价值均不变的物品,然后求解这个 01 背包问题。这样的做法完
全没有改进时间复杂度,但这种方法也指明了将完全背包问题转化为 01 背包问题的思
路:将一种物品拆成多件只能选 0 件或 1 件的 01 背包中的物品。
  更高效的转化方法是:把第 i 种物品拆成费用为 Ci*2^k 、价值为 Wi*2^k 的若干件物
品,其中 k 取遍满足 Ci*2^k ≤ V 的非负整数。
  这是二进制的思想。因为,不管最优策略选几件第 i 种物品,其件数写成二进制后,
总可以表示成若干个 2^k 件物品的和。这样一来就把每种物品拆成 O(log ⌊V /Ci ⌋) 件物
品,是一个很大的改进。

2.5 O(V N ) 的算法

这个算法使用一维数组,先看伪代码:

F [0..V ] ←0
 for i ← 1 to N
  for v ← C i to V
   F [v] ← max(F [v], F [v − Ci ] + W i )

你会发现,这个伪代码与 01 背包问题的伪代码只有 v 的循环次序不同而已。
  为什么这个算法就可行呢?首先想想为什么 01 背包中要按照 v 递减的次序来循环。
让 v 递减是为了保证第 i 次循环中的状态 F [i, v] 是由状态 F [i − 1, v − Ci ] 递推而来。
换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第 i 件物品”这件策略时,依据的是一个绝无已经选入第 i 件物品的子结果 F [i − 1, v − Ci ] 。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第 i 种物品”这种策略时,却正需要一个可能已选入第 i 种物品的子结果 F [i, v − Ci ] ,所以就可以并且必须采用 v递增的顺序循环。这就是这个简单的程序为何成立的道理。
  值得一提的是,上面的伪代码中两层 for 循环的次序可以颠倒。这个结论有可能会带来算法时间常数上的优化。
  这个算法也可以由另外的思路得出。例如,将基本思路中求解 F [i, v − Ci ] 的状态转移方程显式地写出来,代入原方程中,会发现该方程可以等价地变形成这种形式:

F [i, v] = max(F [i − 1, v], F [i, v − Ci ] + Wi )

2.6 小结

完全背包问题也是一个相当基础的背包问题,它有两个状态转移方程。希望读者能
够对这两个状态转移方程都仔细地体会,不仅记住,也要弄明白它们是怎么得出来的,
最好能够自己想一种得到这些方程的方法。
  事实上,对每一道动态规划题目都思考其方程的意义以及如何得来,是加深对动态
规划的理解、提高动态规划功力的好方法。
寒冰王座

#include <cstdio>
#include<algorithm>
#include<string.h>
#define Max(a,b) a>b?a:b
using namespace std;
int main()
{
    int t;
    int dp[10010],val[4]={0,150,200,350},vom[4]={0,150,200,350};
    scanf("%d",&t);
  while(t--)
  {
        int v;
        scanf("%d",&v);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=3;i++)
        {
            for(int j=vom[i];j<=v;j++)
            {
                dp[j]=Max(dp[j],dp[j-vom[i]]+val[i]);
            }
        }
        printf("%d\n",v-dp[v]);
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容