国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

多重背包問題(詳解二進制優(yōu)化原理)

這篇具有很好參考價值的文章主要介紹了多重背包問題(詳解二進制優(yōu)化原理)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、問題描述

二進制多背包問題,# DP與貪心題目,算法,動態(tài)規(guī)劃

二、思路分析

這道題同樣是背包問題,那么它也同樣滿足三個性質(zhì):重疊子問題、最優(yōu)子結構以及無后效性。那么這樣的話,我們依然可以使用動態(tài)規(guī)劃的思路去分析這道題目。那么動態(tài)規(guī)劃的分析主要分為兩步:狀態(tài)轉移方程的書寫以及循環(huán)的設計。

1、狀態(tài)轉移方程

(1)狀態(tài)表示:

我們在前面的兩篇文章中介紹過,對于背包問題而言,我們一般用一個二維數(shù)組來表示dp數(shù)組,即我們經(jīng)常寫的: f ( i , j ) f(i,j) f(i,j)

那么 f ( i , j ) f(i,j) f(i,j)的意思是,當物品數(shù)量為 i i i,自己的背包容量是 j j j的時候,我們所能攜帶的最大價值: f [ i ] [ j ] f[i][j] f[i][j]。

(2)狀態(tài)轉移:

狀態(tài)轉移的目的是為了能夠?qū)⒋笠?guī)模的問題轉化成較小規(guī)模的問題。

背包問題中,狀態(tài)轉移方程的書寫就一個技巧:活在當下

我們此時共用 i i i個物品,我們不可能一下子就同時做出多個決策,從而得到最優(yōu)解。我們就看眼前,我們眼前的就是第 i i i個物品,而我們要做的決策就是,第 i i i個物品到底選不選,選的話,在背包容量允許的條件下,我們選幾個?

如果我們不選的話,我們就能寫出下列的方程:

f ( i , j ) = f ( i ? 1 , j ) f(i,j)=f(i-1,j) f(i,j)=f(i?1,j)

由于我們不選第 i i i個物品,所以我們只需要考慮前 i ? 1 i-1 i?1個。這樣我們就把規(guī)模從 i i i降低到了 i ? 1 i-1 i?1。

假設我們選的話,那么就能夠?qū)懗上铝行问剑海?span id="n5n3t3z" class="katex--inline"> v [ i ] v[i] v[i]表示第 i i i個物品的體積, w [ i ] w[i] w[i]表示第 i i i個物品的價值)

f ( i , j ) = f ( i ? 1 , j ? v [ i ] ? k ) + w [ i ] ? k f(i,j)=f(i-1,j-v[i]*k)+w[i]*k f(i,j)=f(i?1,j?v[i]?k)+w[i]?k

上述等式成立的前提是保證: j ≥ v [ i ] ? k j\geq v[i]*k jv[i]?k

我們只需要在上述的這些情況中取一個最大值即可:

所以我們的狀態(tài)轉移方程可以表示為:

f ( i , j ) = m a x { f ( i ? 1 , j ) f ( i ? 1 , j ? v [ i ] ) + w [ i ] j ≥ v [ i ] f ( i ? 1 , j ? v [ i ] ? 2 ) + w [ i ] ? 2 j ≥ v [ i ] ? 2 . . . . . . f ( i ? 1 , j ? v [ i ] ? k ) + w [ i ] ? k j ≥ v [ i ] ? k f(i,j)=max \begin{cases} f(i-1,j)\\ f(i-1,j-v[i])+w[i] &j\geq v[i]\\ f(i-1,j-v[i]*2)+w[i]*2 &j\geq v[i]*2\\ ......\\ f(i-1,j-v[i]*k)+w[i]*k&j\geq v[i]*k \end{cases} f(i,j)=max? ? ??f(i?1,j)f(i?1,j?v[i])+w[i]f(i?1,j?v[i]?2)+w[i]?2......f(i?1,j?v[i]?k)+w[i]?k?jv[i]jv[i]?2jv[i]?k?

2、循環(huán)設計

我們的循環(huán)和之前所介紹的01背包問題、完全背包問題的循環(huán)設計是一樣的,最外層循環(huán)是背包的規(guī)模從小到大,第二層的循環(huán)是背包的容量,從小到大。

三、代碼模板

1、樸素版

我們綜合上面的思路,就能夠?qū)懗鱿旅娴拇a:

#include<iostream>
using namespace std;
const int N=110;
int f[N][N],v[N],w[N],q[N];
int n,m;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",v+i,w+i,q+i);
    }
    for(int i=1;i<=n;i++)//枚舉物品規(guī)模
    {
        for(int j=0;j<=m;j++)//枚舉背包容量
        {
            for(int k=0;k*v[i]<=j&&k<=q[i];k++)//書寫狀態(tài)轉移方程
            {
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
            }
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

2、優(yōu)化版

我們發(fā)現(xiàn)上面的這個樸素版代碼包含了三重循環(huán),那么我們?nèi)绾谓档鸵粚友h(huán)呢?

其實,我們的多重背包可以轉化成01背包問題。這樣講肯定很抽象,大家可以看下面的圖:
二進制多背包問題,# DP與貪心題目,算法,動態(tài)規(guī)劃
但是這樣做的話只是形式上做了優(yōu)化,從 n 3 n^3 n3 n 2 n^2 n2,但實際上依舊是一個 n 3 n^3 n3的時間復雜度。

而這樣沒有成功優(yōu)化的原因是因為我們有 n n n i i i物品,就需要重復 n n n個i物品。那么我們是否存在一種方式,我們不需要枚舉 n n n次i物品,就能夠表示 n n n i i i物品呢?

答案是有的。

我們的十進制數(shù)可以用二進制數(shù)來表示。

假設我們的二進制位有4位:

那么我們能表示的范圍是: 0000 0000 0000 ~ 1111 1111 1111。

1111 = 1000 + 0100 + 0010 + 0001 1111=1000+0100+0010+0001 1111=1000+0100+0010+0001

上面右側的四個部分組成了這個數(shù)字。

我們可以從形式上掌握一下,這個四個部分所代表的含義就是對應的位數(shù)是1。

1000 1000 1000:第四位是1
0100 0100 0100:第三位是1
0010 0010 0010:第二位是1
0001 0001 0001:第一位是1

接著我們發(fā)現(xiàn), 0000 0000 0000 1111 1111 1111之間的任何一個數(shù)字,其實無非是某位是0,某位是1。如果某位是1,我們只需要加上上面四個數(shù)字中的其中一個。

例如:
1001 = 1000 + 0001 1001=1000+0001 1001=1000+0001
1101 = 1000 + 0001 + 0100 1101=1000+0001+0100 1101=1000+0001+0100

因此我們就能夠得到一個結論,我們能夠有這四個數(shù)字表示 0000 0000 0000 1111 1111 1111之間的所有數(shù)字。

轉換成十進制而言,就是說我們能夠用 1 1 1, 2 2 2, 4 4 4, 8 8 8表示出 0 0 0 15 15 15之間的任何數(shù)字。

所以,我們可以利用幾個 2 k 2^k 2k,其中 ( k = 0 , 1 , 2 , . . . ) (k=0,1,2,...) k=01,2...,來表達一個范圍內(nèi)的所有數(shù)字。根據(jù)我們剛才的推導,所能表示的范圍其實就是我們剛剛這幾個數(shù)加在一起時的值,其實就是一個等比數(shù)列求和。

用數(shù)學公式表達就是

我們可以利用: 2 0 、 2 1 、 2 2 、 2 3 、 . . . 、 2 k 2^0、2^1、2^2、2^3、... 、2^k 20、21、22、23、...2k表示 0 0 0 ~ 2(k+1) ? 1 -1 ?1之間的所有數(shù)字。

那么如果我們的要表達的200

那么我們可以利用:
2 0 、 2 1 、 2 2 、 2 3 、 2 4 、 2 5 、 2 6 2^0、2^1、2^2、2^3、2^4、2^5、2^6 2021、22、23、2425、26

這幾個數(shù)能表達的最大值是: 2 7 ? 1 = 127 2^7-1=127 27?1=127

那么從128到200怎么表示呢?

其實我們只需要多加一個73即可。

也就是說,我們可以用:

2 0 、 2 1 、 2 2 、 2 3 、 2 4 、 2 5 、 2 6 、 73 2^0、2^1、2^2、2^3、2^4、2^5、2^6 、73 2021、22、23、24、2526、73
來表達0-200。

為什么呢?

我們只用前面的這些 2 k 2^k 2k。那么我們能表示的是 0 ? 127 0-127 0?127。
如果我們每次選擇的時候都加上一個73,我們能表示的范圍就是:
73 ? 200 73-200 73?200

雖然兩部分之間有一點重疊的部分,但是重疊的話,無非就是我們重復計算了幾個相同情況而已,并不影響我們結果的正確性。

那么我們發(fā)現(xiàn),此時我們利用 O ( l o g n ) O(logn) O(logn)級別的數(shù)字表示了 O ( n ) O(n) O(n)。

時間上做了非常大的優(yōu)化。

而這種優(yōu)化方式被稱作二進制優(yōu)化。

如圖所示:

二進制多背包問題,# DP與貪心題目,算法,動態(tài)規(guī)劃
根據(jù)上面的思路,我們就能夠?qū)懗鱿旅娴膬?yōu)化版本的代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-621491.html

#include<iostream>
using namespace std;
const int N=3e4+10;
int dp[N],v[N],w[N];
int n,m;
int main()
{
    cin>>n>>m;
    int cnt=1;
    for(int i=1;i<=n;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        int k=1;
        //進行 “打包” 轉換:二進制優(yōu)化,轉換成01背包
        while(k<c)
        {
            v[cnt]=k*a,w[cnt++]=k*b;
            c-=k;
            k*=2;
        }
        if(c>0)
            v[cnt]=c*a,w[cnt++]=c*b;
    }
    //利用01背包中的空間優(yōu)化模板求解。
    for(int i=1;i<=cnt;i++)
        for(int j=m;j>=v[i];j--)
                dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    cout<<dp[m]<<endl;
    return 0;
}

到了這里,關于多重背包問題(詳解二進制優(yōu)化原理)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 二進制加密PHP Webshell原理及簡單實現(xiàn)

    二進制加密PHP Webshell原理及簡單實現(xiàn)

    今天繼續(xù)給大家介紹滲透測試相關知識,本文主要內(nèi)容是二進制加密PHP Webshell原理及簡單實現(xiàn)。 免責聲明: 本文所介紹的內(nèi)容僅做學習交流使用,嚴禁利用文中技術進行非法行為,否則造成一切嚴重后果自負! 再次強調(diào):嚴禁對未授權設備進行滲透測試! 為了躲避WAF、殺軟

    2023年04月09日
    瀏覽(26)
  • C/C++ 高精度(加減乘除)算法二進制優(yōu)化

    C/C++ 高精度(加減乘除)算法二進制優(yōu)化

    第一章 簡單實現(xiàn) 第二章 壓位優(yōu)化 第三章 二進制優(yōu)化(本章) 上一章《C/C++ 高精度(加減乘除)算法壓位優(yōu)化》實現(xiàn)了優(yōu)化的高精度計算,采用int32的整型數(shù)組每個元素可以儲存9個10進制數(shù)字,想要再進一步優(yōu)化計算速度,可以改變數(shù)據(jù)存儲方式,采用二進制存儲數(shù)字。依然采

    2024年02月11日
    瀏覽(22)
  • C#對象二進制序列化優(yōu)化:位域技術實現(xiàn)極限壓縮

    目錄 1. 引言 2. 優(yōu)化過程 2.1. 進程對象定義與初步分析 2.2. 排除Json序列化 2.3. 使用BinaryWriter進行二進制序列化 2.4. 數(shù)據(jù)類型調(diào)整 2.5. 再次數(shù)據(jù)類型調(diào)整與位域優(yōu)化 3. 優(yōu)化效果與總結 在操作系統(tǒng)中,進程信息對于系統(tǒng)監(jiān)控和性能分析至關重要。假設我們需要開發(fā)一個監(jiān)控程序

    2024年01月22日
    瀏覽(23)
  • [動態(tài)規(guī)劃,二進制狀態(tài)壓縮] 旅行商問題

    題目描述 一個國家有 n 個城市,每兩個城市之間都開設有航班,從城市 i 到城市 j 的航班價格為 cost[i, j] ,而且往、返航班的價格相同。 售貨商要從一個城市出發(fā),途徑每個城市 1 次(且每個城市只能經(jīng)過 1 次),最終返回出發(fā)地,而且他的交通工具只有航班,請求出他旅

    2024年01月24日
    瀏覽(22)
  • 多重背包問題——單調(diào)隊列優(yōu)化

    多重背包問題——單調(diào)隊列優(yōu)化

    我們在之前的文章中曾經(jīng)講解過多重背包問題,當時我們講解了兩種方法,一種方法就是三重循環(huán),這種方法最為樸素好想。但是這種方法的時間復雜度非常高,后來我們想到了二進制優(yōu)化的方式。那么今天我們將再介紹一種更好的優(yōu)化方式——單調(diào)隊列優(yōu)化。 在講解這種優(yōu)

    2024年02月15日
    瀏覽(28)
  • [ARM匯編]計算機原理與數(shù)制基礎—1.1.2 二進制與十進制數(shù)制轉換

    [ARM匯編]計算機原理與數(shù)制基礎—1.1.2 二進制與十進制數(shù)制轉換

    在計算機中,我們通常使用二進制數(shù)制來表示數(shù)據(jù),因為計算機的基本電平只有兩種狀態(tài):高電平(通常表示為 1)和低電平(通常表示為 0)。而在我們的日常生活中,我們習慣使用十進制數(shù)制。為了方便理解,我們需要掌握二進制與十進制之間的轉換方法。 二進制轉十進

    2024年02月08日
    瀏覽(22)
  • 三十八、動態(tài)規(guī)劃——背包問題( 01 背包 + 完全背包 + 多重背包 + 分組背包 + 優(yōu)化)

    三十八、動態(tài)規(guī)劃——背包問題( 01 背包 + 完全背包 + 多重背包 + 分組背包 + 優(yōu)化)

    0 1 背包問題: 條件:N 個物品容量為 V 的背包,每件物品最多用 1 次,其中物品信息體積為 Vi,價值為 Wi。 目標:選出物品,使價值最大(不一定裝滿背包)。 特點:每件物品 最多只用 1 次 完全背包問題: 特點:每一件物品都有 無限個 多重背包問題: 特點:每個物品

    2024年02月07日
    瀏覽(24)
  • [ARM匯編]計算機原理與數(shù)制基礎—1.1.3 二進制補碼

    [ARM匯編]計算機原理與數(shù)制基礎—1.1.3 二進制補碼

    在計算機中,為了表示有符號整數(shù)(即正數(shù)和負數(shù)),通常采用二進制補碼表示法。二進制補碼不僅可以表示負數(shù),還能簡化計算機的加法和減法運算。接下來,我們將介紹二進制補碼的概念及其計算方法。 原碼、反碼和補碼 在討論補碼之前,我們先了解一下原碼和反碼的

    2024年02月08日
    瀏覽(26)
  • C# 流Stream詳解(1)——讀寫txt和二進制文件

    【讀寫txt文件】 電腦手機上有各種各樣的文件,例如視頻文件、圖片文件、文本文件,其中讀寫txt文件是最簡單的,有多種方式, 使用StreamReader和StreamWriter 使用TextReader和TextWriter? ?使用FileStream 使用File類提供的靜態(tài)方法 上面幾種方法代碼都很長,一般來說我們幾乎不會使

    2024年02月06日
    瀏覽(24)
  • linux二進制文件分析三大工具詳解(ldd、readelf、nm)

    linux二進制文件分析三大工具詳解(ldd、readelf、nm)

    測試代碼源碼、源碼如下: 編譯命令 ldd 是 Linux 下的一個命令,用于查看可執(zhí)行文件或共享庫文件的動態(tài)鏈接庫依賴關系。通過 ldd 命令,你可以確定一個可執(zhí)行文件或共享庫文件所依賴的動態(tài)鏈接庫(也就是它們在運行時需要加載的庫文件)。 OPTIONS(可選) : ldd 命令支

    2024年02月06日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包