• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            雁過(guò)無(wú)痕

            多重背包O(N*V)算法詳解(使用單調(diào)隊(duì)列)

             

            多重背包問(wèn)題:

            N種物品和容量為V的背包,若第i種物品,容量為v[i],價(jià)值為w[i],共有n[i]件。怎樣裝才能使背包內(nèi)的物品總價(jià)值最大?

             

            網(wǎng)上關(guān)于“多重背包”的資料倒是不少,但是關(guān)于怎么實(shí)現(xiàn)O(N*V)算法的資料,真得好少呀,關(guān)于“單調(diào)隊(duì)列”那部分算法,又沒(méi)說(shuō)明得很清楚,看了幾遍沒(méi)看懂原理,只好自己動(dòng)腦去想怎么實(shí)現(xiàn)O(N*V)算法。

             

            若用F[i][j]表示對(duì)容量為j的背包,處理完前i種物品后,背包內(nèi)物品可達(dá)到的最大總價(jià)值,并記m[i] = min(n[i], j / v[i])。放入背包的第i種物品的數(shù)目可以是:012……,可得:

            F[i][j] = max { F[i - 1] [j – k * v[i] ] + k * w[i] }  (0 <= k <= m[i])      

               

            如何在O(1)時(shí)間內(nèi)求出F[i][j]呢?

            先看一個(gè)例子:取m[i] = 2, v[i] = v, w[i] = w, V > 9 * v

            并假設(shè) f(j) = F[i - 1][j],觀察公式右邊要求最大值的幾項(xiàng):

            j = 6*v:   f(6*v)f(5*v)+wf(4*v)+2*w 這三個(gè)中的最大值

            j = 5*v:   f(5*v)f(4*v)+wf(3*v)+2*w 這三個(gè)中的最大值

            j = 4*v:   f(4*v)f(3*v)+wf(2*v)+2*w 這三個(gè)中的最大值

            顯然,公式㈠右邊求最大值的幾項(xiàng)隨j值改變而改變,但如果將j = 6*v時(shí),每項(xiàng)減去6*wj=5*v時(shí),每項(xiàng)減去5*wj=4*v時(shí),每項(xiàng)減去4*w,就得到:

            j = 6*v:   f(6*v)-6*wf(5*v)-5*wf(4*v)-4*w 這三個(gè)中的最大值

            j = 5*v:   f(5*v)-5*wf(4*v)-4*wf(3*v)-3*w 這三個(gè)中的最大值

            j = 4*v:   f(4*v)-4*wf(3*v)-3*wf(2*v)-2*w 這三個(gè)中的最大值

            很明顯,要求最大值的那些項(xiàng),有很多重復(fù)。

             

            根據(jù)這個(gè)思路,可以對(duì)原來(lái)的公式進(jìn)行如下調(diào)整:

            假設(shè)d = v[i]a = j / db = j % d,即 j = a * d + b,代入公式㈠,并用k替換a - k得:

            F[i][j] = max { F[i - 1] [b + k * d] - k * w[i] } + a * w[i]   (a – m[i] <= k <= a)   

             

            對(duì)F[i - 1][y] y= b  b+d  b+2d  b+3d  b+4d  b+5d  b+6d    j

            F[i][j]就是求j的前面m[i] + 1個(gè)數(shù)對(duì)應(yīng)的F[i - 1] [b + k * d] - k * w[i]的最大值,加上a * w[i],如果將F[i][j]前面所有的F[i - 1][b + k * d] – k * w放入到一個(gè)隊(duì)列,那么,F[i][j]就是求這個(gè)隊(duì)列最大長(zhǎng)度為m[i] + 1時(shí),隊(duì)列中元素的最大值,加上a * w[i]因而原問(wèn)題可以轉(zhuǎn)化為:O(1)時(shí)間內(nèi)求一個(gè)隊(duì)列的最大值

            該問(wèn)題可以這樣解決:

            ① 用另一個(gè)隊(duì)列B記錄指定隊(duì)列的最大值(或者記錄最大值的地址),并通過(guò)下面兩個(gè)操作保證隊(duì)列B的第一個(gè)元素(或其所指向的元素)一定是指定隊(duì)列的當(dāng)前最大值。

            ② 當(dāng)指定隊(duì)列有元素M進(jìn)入時(shí),刪除隊(duì)列B中的比M小的(或隊(duì)列B中所指向的元素小等于M的)所有元素,并將元素M(或其地址)存入隊(duì)列B

            ③ 當(dāng)指定隊(duì)列有元素M離開(kāi)時(shí),隊(duì)列B中的第一個(gè)元素若與M相等(或隊(duì)列B第一個(gè)元素的地址與M相等),則隊(duì)列B的第一個(gè)元素也離隊(duì)。

            經(jīng)過(guò)上述處理,可以保證隊(duì)列B中的第一個(gè)元素(或其指向的元素)一定是所指定隊(duì)列所有元素的最大值。顯然隊(duì)列B的元素(或其所指向的元素)是單調(diào)遞減的,這應(yīng)該就是《背包九講》中的提到的“單調(diào)隊(duì)列”吧,初看的時(shí)候被這個(gè)概念弄得稀里糊涂,網(wǎng)上的資料提到“維護(hù)隊(duì)列的最大值”,剛開(kāi)始還以為是維護(hù)這個(gè)單調(diào)隊(duì)列的最大值,對(duì)其采用的算法,越看越糊涂。其實(shí),只要明白用一個(gè)“輔助隊(duì)列”,求另一個(gè)隊(duì)列的最值,那么具體的算法,和該“輔助隊(duì)列”的性質(zhì)(單調(diào)變化),都很容易推導(dǎo)出來(lái)。

            在多重背包問(wèn)題中,所有要進(jìn)入隊(duì)列的元素個(gè)數(shù)的上限值是已知的,可以直接用一個(gè)大數(shù)組模擬隊(duì)列。

            “多重背包”通用模板



            多重背包特例:物品價(jià)值和體積相等(w = v)

            由于w = v,上面的代碼可進(jìn)行如下修改:

            入隊(duì)的元素: tt = f[k] - (k / v) * w = f[k] - (k - j) = f[k] - k + j

                返回的最大值:*qb + (k / v) * w =  *qb + k - j

            由于j是定值,可調(diào)整入隊(duì)的元素為: f[k] - k,最大值為 *qb + k

             

            但這種做法相當(dāng)?shù)托А?shí)際上,這相當(dāng)于一個(gè)“覆蓋”問(wèn)題:在放入前i個(gè)物品后,體積為j的背包,只存在兩種狀態(tài):是否能剛好裝滿,也就是,是否能被覆蓋。因而只要記錄下該狀態(tài)就可以了,前面的分析進(jìn)行相應(yīng)的調(diào)整:

            對(duì)F[i - 1][y] y= b  b+d  b+2d  b+3d  b+4d  b+5d  b+6d    j

            F[i][j]就是求j的前面m[i] + 1個(gè)數(shù)對(duì)應(yīng)的F[i - 1] [b + k * d](其值為01)的最大值,即j前面的m[i] + 1個(gè)01數(shù)據(jù)中是否存在1,這又可以簡(jiǎn)化為判斷它們的和是否不等于0


            pack-01

             

            另外,可以倒著讀數(shù)據(jù),這樣就不需要額外使用一個(gè)數(shù)組存放臨時(shí)數(shù)據(jù):


            pack-02

             

            前面的代碼,都在循環(huán)中對(duì)隊(duì)列的元素個(gè)數(shù)進(jìn)行判斷,這可以通過(guò)下面的方法避免,將循環(huán)拆分成兩部分:一部分都有入隊(duì)和出隊(duì)操作、另一部分只有入隊(duì)(或出隊(duì))操作。

             

            對(duì)該特例,還有一種O(N * V)解法:用一個(gè)數(shù)組記錄當(dāng)前物品已經(jīng)使用數(shù),關(guān)鍵代碼:

            if (! f[i] && f[i - v] && count[i - v] < n)

            f[i] = true, count[i] = count[i - v] + 1;

            每計(jì)算一類物品,count數(shù)組都要初始化一次,比較費(fèi)時(shí),可以再用一個(gè)數(shù)組記錄上一次處理的物品編號(hào),通過(guò)判斷上一次放入那一類的物品編號(hào)與當(dāng)前這類物品編號(hào)是否一致(不一致時(shí),相當(dāng)于count[i]值為0的情況),從而避免對(duì)count數(shù)組的初始化操作。還可以將初始化count數(shù)組和后面的循環(huán)整合在一起。


            pack-1

            pack-2

            pack-4


            POJ 1742
            :有若干不同面值的紙幣,問(wèn)能組合出1m中的幾種面值?


            poj 1742

            用自己隨機(jī)生成的數(shù)據(jù)測(cè)試了下,上面提到的幾種方法,所用時(shí)間都是7秒多點(diǎn),有排序的比沒(méi)排序的稍微快點(diǎn)。但在POJ上提交的結(jié)果,不同代碼的耗時(shí)相差挺大,快的在1秒左右,慢的接近1.5秒。

             


            還有一種特例:

            給定面值為125的紙幣若干個(gè),問(wèn)其所不能支付的最低價(jià)格(假設(shè)為自然數(shù))。

            這可以用多重背包(或母函數(shù))來(lái)解決,但實(shí)際上是有O(1)解法的。

            posted on 2010-09-01 23:25 flyinghearts 閱讀(6536) 評(píng)論(5)  編輯 收藏 引用 所屬分類: 算法

            評(píng)論

            # re: 多重背包O(N*V)算法詳解(使用單調(diào)隊(duì)列) 2010-10-02 11:56 040374
            能把用單調(diào)隊(duì)列解poj1742的思想寫(xiě)得更詳細(xì)點(diǎn)嗎?thx  回復(fù)  更多評(píng)論
              

            # re: 多重背包O(N*V)算法詳解(使用單調(diào)隊(duì)列) 2010-10-04 18:44 flyinghearts
            @040374
            在V=W這種特例中,單調(diào)隊(duì)列是可以不用的,只要采用隊(duì)列思想就可以了。
            對(duì)每個(gè)值只記錄兩種狀態(tài),要判斷的是:(間隔為v)的連續(xù)n個(gè)狀態(tài)中是否為1,這等價(jià)于判斷它們的和是否不為0,
            如果從前往后讀取這些狀態(tài)時(shí),就需要一個(gè)臨時(shí)數(shù)組,不然新?tīng)顟B(tài)值會(huì)覆蓋舊狀態(tài)值。
            但是,我們可以從后往前讀取這些狀態(tài)值,這樣就不需要臨時(shí)數(shù)組了。

            對(duì)V=W這種特例,“狀態(tài)+計(jì)數(shù)”(這也是很多網(wǎng)友采取的方法)這種方法,效率會(huì)更高,
            一般來(lái)說(shuō),在判斷狀態(tài)中后期,狀態(tài)為真的占大多數(shù),這樣采用計(jì)數(shù)的方法就只要訪問(wèn)某個(gè)狀態(tài)值一次,
            而上面的方法,則要兩次(進(jìn)出隊(duì)各一次)。

              回復(fù)  更多評(píng)論
              

            # re: 多重背包O(N*V)算法詳解(使用單調(diào)隊(duì)列)[未登錄](méi) 2012-11-16 11:11 kai
            前面部分講的很清楚,謝謝

            多重背包特例:物品價(jià)值和體積相等(w = v)

            tt = f[k] - (k / v) * w = f[k] - (k - j) = f[k] - k + j

            好像沒(méi)說(shuō)清楚

            改成

            因?yàn)?br>F[i - 1] [b + k * d] - k * w[i]

            d = w



            b + k * d = k'
            ->
            k = (k' - b)/d
            ->
            tt = f[k'] - ( (k' - b)/ d) * w = f[k'] - (k'-b) = f[k'] - k' + b

            在循環(huán)
            for (int k = j, i = 0; k <= V; k += v, ++i)

            里面

            b其實(shí)是j, k' 其實(shí)是k

            f[k'] - k' + b = f[k] - k + j
              回復(fù)  更多評(píng)論
              

            # re: 多重背包O(N*V)算法詳解(使用單調(diào)隊(duì)列)[未登錄](méi) 2012-11-18 06:01 kai
            > 另外,可以倒著讀數(shù)據(jù),這樣就不需要額外使用一個(gè)數(shù)組存放臨時(shí)數(shù)據(jù):

            正向著來(lái)為什么不可以?好像也說(shuō)的通吧  回復(fù)  更多評(píng)論
              

            # re: 多重背包O(N*V)算法詳解(使用單調(diào)隊(duì)列) 2014-10-12 09:59 天天好贏錢(qián)
            有入口簡(jiǎn)而言之是指在發(fā)布站點(diǎn)的相關(guān)頻道可以看到軟文標(biāo)題,點(diǎn)擊標(biāo)題進(jìn)入www.fuc688.com軟文內(nèi)容頁(yè)面;而無(wú)入口則是指只提供文章內(nèi)容的網(wǎng)址鏈接,在頻道頁(yè)面找不到軟文標(biāo)題。有入口的軟文有助于線上網(wǎng)友的瀏覽,提高點(diǎn)擊率,可更好地?cái)U(kuò)大宣傳面;無(wú)入口的軟文適合做成書(shū)面的形式,用word或ppt等做成效果圖表,適用于線下的講座、匯報(bào)等。我們發(fā)布的軟文發(fā)布絕大部分都  回復(fù)  更多評(píng)論
              

            亚洲а∨天堂久久精品| 欧美无乱码久久久免费午夜一区二区三区中文字幕 | 国产精品九九久久精品女同亚洲欧美日韩综合区 | 国产精品久久久天天影视香蕉 | 久久国产精品无码HDAV| 久久性生大片免费观看性| 久久66热人妻偷产精品9| 久久伊人精品一区二区三区| 新狼窝色AV性久久久久久| 久久久精品波多野结衣| 99久久精品九九亚洲精品| 久久精品一本到99热免费| 久久99精品免费一区二区| 精品久久久久久久中文字幕| 伊人久久大香线蕉亚洲| 亚洲精品乱码久久久久久按摩 | 久久婷婷五月综合色奶水99啪| 久久免费99精品国产自在现线| 亚洲精品乱码久久久久久按摩 | 久久精品国产久精国产思思| 合区精品久久久中文字幕一区 | 亚洲国产精品无码久久久久久曰| 日韩欧美亚洲综合久久影院d3| 日韩精品久久无码人妻中文字幕| 伊人久久大香线蕉亚洲五月天| 免费一级做a爰片久久毛片潮| 久久99国产精品久久99果冻传媒| 国产国产成人精品久久| 久久精品视频免费| 国产精品无码久久综合| 亚洲国产另类久久久精品黑人| 伊人久久大香线蕉成人| 囯产极品美女高潮无套久久久| 日本精品久久久久影院日本| 久久精品亚洲男人的天堂| 97精品国产97久久久久久免费| 色综合色天天久久婷婷基地| 丁香五月网久久综合| 国产亚洲美女精品久久久久狼| 97久久精品国产精品青草| 亚洲AV成人无码久久精品老人|