作小偷也要會動態規劃——輕鬆解決"01揹包問題"

前言

小偷不可怕,就怕小偷有文化,更怕小偷學過動態規劃。html

正文

白玉湯曾是江湖上赫赫有名的盜聖,奈何歲月不饒人,上了年紀後腿腳便不利索了,無奈一身的本領卻沒有個傳承之人。這天,一位少年前來拜師學藝,但願白玉湯能在偷盜一事上指點一二。白玉湯見這少年骨骼清奇,心裏有收其爲徒的想法,便出了下面這道題考考少年:c++

話說地主金館長家有個專門藏金銀財寶的房間,潛入後發現可偷之物太多,奈何自身負重能力有限,你的包只能承重20kg的物品,並且每一個物品的價值又都不同,那麼問題來了,將哪些物品裝入揹包才能不枉此行,使價值總和最大呢?物品重量和其價值的關係以下:bash

編號 重量(w) 價值(v)
1 2 3
2 3 4
3 4 5
4 5 8
5 9 10

少年一看,這不就是一道「01揹包問題嗎」,說完便在地上作出了以下分析:ide

設咱們的揹包裏面的物品價值爲b,給揹包添加兩個參數:k和c,即b(k,c),那麼b(k,c)又表示什麼什麼意思呢?網站

k表示你面對的物品編號,即1~5, c表示你面對k號物品時,揹包的剩餘容量 b(k,c)表示面對k號物品,並做出拿或不拿的選擇以後,揹包裏面的物品總價值編碼

舉個例子,b(2,20)表示的是,在你的揹包容量爲20的狀況下,當你面對2號物品時並做出拿或者不拿的選擇後,揹包中物品的總價值。spa

瞭解了這個概念後咱們繼續: 假設你如今碰見了第k號物品,此時你的揹包容量爲c,你得作出一個決策,到底要不要拿走第k件物品呢?那麼拿不拿的前提是啥?固然是這個物品重不重,能不能塞到包裏。因此第一種狀況就出現了:3d

  1. 若是第k件物品的重量w[k]比此時的揹包的剩餘重量c大了,那我確定是拿不動了,即w[k]>c。因此此時包中物品的價值就是我拿的前一個物品以後包中的價值,即 b(k,c)=b(k-1,c).包中剩餘空間不變,仍是c。

那麼第二種狀況,若是我拿得動第k件物品,即第k件物品的重量w[k]<c,面對k號物品,無外乎兩種選擇,拿或者不拿,這時我就要根據拿走以後產生的效益進行決策了:code

  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]}

剩下的只須要比較小這兩種方式誰的效益大便可。思惟導圖以下: cdn

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

若是你以爲本文還不錯,麻煩隨手點贊與轉發吧。😋(撲通

點贊與轉發是最好的支持

相關文章
相關標籤/搜索