做小偷也要会动态规划——轻松解决"01背包问题"

前言

小偷不可怕,就怕小偷有文化,更怕小偷学过动态规划。

正文

白玉汤曾是江湖上赫赫有名的盗圣,奈何岁月不饶人,上了年纪后腿脚便不利索了,无奈一身的本领却没有个传承之人。这天,一位少年前来拜师学艺,希望白玉汤能在偷盗一事上指点一二。白玉汤见这少年骨骼清奇,内心有收其为徒的想法,便出了下面这道题考考少年:

话说地主金馆长家有个专门藏金银财宝的房间,潜入后发现可偷之物太多,奈何自身负重能力有限,你的包只能承重20kg的物品,而且每个物品的价值又都不一样,那么问题来了,将哪些物品装入背包才能不虚此行,使价值总和最大呢?物品重量和其价值的关系如下:

编号 重量(w) 价值(v)
1 2 3
2 3 4
3 4 5
4 5 8
5 9 10

少年一看,这不就是一道“01背包问题吗”,说完便在地上做出了如下分析:

设我们的背包里面的物品价值为b,给背包添加两个参数:k和c,即b(k,c),那么b(k,c)又表示什么什么意思呢?

k表示你面对的物品编号,即1~5,
c表示你面对k号物品时,背包的剩余容量
b(k,c)表示面对k号物品,并作出拿或不拿的选择之后,背包里面的物品总价值

举个例子,b(2,20)表示的是,在你的背包容量为20的情况下,当你面对2号物品时并作出拿或者不拿的选择后,背包中物品的总价值。

了解了这个概念后我们继续:
假设你现在遇见了第k号物品,此时你的背包容量为c,你得做出一个决策,到底要不要拿走第k件物品呢?那么拿不拿的前提是啥?当然是这个物品重不重,能不能塞到包里。所以第一种情况就出现了:

  1. 如果第k件物品的重量w[k]比此时的背包的剩余重量c大了,那我肯定是拿不动了,即w[k]>c。所以此时包中物品的价值就是我拿的前一个物品之后包中的价值,即 b(k,c)=b(k-1,c).包中剩余空间不变,还是c。

那么第二种情况,如果我拿得动第k件物品,即第k件物品的重量w[k]<c,面对k号物品,无外乎两种选择,拿或者不拿,这时我就要根据拿走之后产生的效益进行决策了:

  1. 不拿k号物品,那么此时包中物品的总价值b(k,c)=b(k-1,c),和第一种拿不动k号物品的一样。
  2. 拿走k号物品,那么此时包中物品的总价值b(k,c)=b(k-1,c-w[k])+v[k]拿了第k件物品后,那我的包中的价值肯定就是原先的价值再加上第k件物品的价值,而且拿了之后包中的剩余容量就为c-w[k]了。 总结一下,就是如下的公式了:b(k,c)=max{b(k-1,c),b(k-1,c-w[k])+v[k]}

剩下的只需要比较小这两种方式谁的效益大即可。思维导图如下:


01背包问题的递推公式

看懂以上描述后,编码就很简单了,这里我用Java写出来

class Main {
    public static void main(String[] args) {
        int[] w = { 0, 2, 3, 4, 5, 9 };
        int[] v = { 0, 3, 4, 5, 8, 10 };
        int N = 6, W = 21;
        int[][] b = new int[N][W];
        for (int k = 1; k < N; k++) {
            for (int c = 1; c < W; c++) {
                if (w[k] > c) {
                    b[k][c] = b[k - 1][c];
                } else {
                    int value1 = b[k - 1][c - w[k]] + v[k]; // 拿第k件物品
                    int value2 = b[k - 1][c]; // 不拿第k件物品
                    b[k][c] = Math.max(value1, value2);
                }
            }
        }
        System.out.println(b[5][20]);
    }
}

结果为26

最后

其实公众号之前有发过一篇类似的“01背包问题”的解析——《使用动态规划解决童年难题》,网上大多数的博客在解析“01背包问题”时也都是采用画图的形式,类似于这样的:

01背包问题的图解

但是我当时看的时候真的是一脸懵逼,然后再带着图去看长篇的解析就更混乱了。希望你能在理解了上述流程之后,再回过头去看公众号之前的文章,对那个图的理解应该就会更加深刻了,二者一起看,辅助理解。

推荐

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