日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ 多重背包状态转移方程_【模板】各种背包问题amp;讲解

發布時間:2025/4/5 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ 多重背包状态转移方程_【模板】各种背包问题amp;讲解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【模板】各種背包問題&講解

?背包問題集合

  一般來說,動態規劃(DP)都是初學者最難闖過的一關,而在這里詳細解說動態規劃的一種經典題型:背包問題。

這里介紹的背包分為以下幾種:01背包,完全背包,多重背包,混合背包,二維費用的背包。(以后會持續更新)

【一:01背包】

首先放上例題:

01背包問題

【題目描述】:

一個旅行者有一個最多能裝M公斤的背包,現在有n件物品,他們的重量分別是W1,W2…Wn,它們的價值分別是C1,C2……Cn,求旅行者能夠獲得的最大總價值。

【輸入格式】:

第一行:兩個整數,M,(背包容量,M<=200)和N(物品數量N<=30)

第2至N+1行,每行兩個整數,Wi,Ci,表示每個物品的重量和價值。

【輸出格式】:僅一行,一個數,表示最大總價值。

【輸入樣例#1】:

10 4

2 1

3 3

4 5

7 9

【輸出樣例#1】:12

【輸入樣例#2】:

8 4

5 6

4 2

1 2

01背包問題可以說是最簡單的背包問題,簡單之處就在:他的每一個物品都只有一個。

首先定義一個f[MAXN][MAXN]數組,用來記錄最大價值。即:f[i][v]表示的就是當前i件物品放入一個容量為v的背包的時候可以獲得的最大價值。

01背包的狀態轉移方程式便是:f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+c[i])。

眾所周知DP問題最重要的便是狀態轉移方程式了,那么這個狀態轉移方程式究竟是怎么來的呢??

詳解來啦“!!!

既然說了是“將第i件物品放入背包”,那么如果只考慮第i件物品的方式策略,那么就只和第i-1件物品有關了,如果是放第i件物品,那么問題就轉化為:“前i-1件物品放入容量為v的背包中”,此時能夠獲得的最大價值就是f[i-1][v-w[i]],也就是第i-1件物品放入容量為v(原來的總容量)減去w[i](第i件物品的占容)產生的最優價值,再加上放通過入第i件物品增加的價值c[i]。

那么放入第i件物品產生的最大價值就是要在”放“,或者是”不放“中選擇了,”不放“的話,產生的價值就是f[i-1][v],”放“的話,產生的最大價值就是,f[i-1][v-w[i]]+c[i])。那么我們應該怎么選擇呢,很簡單,取最大的,就是產生的最大價值啦。

若物品數量為n,背包總容量為m,那么循環到最后,答案也就是f[n][m]啦。

那么附上代碼:::

#include#define MAXN 0x7ffusing namespace std;int m,n,w[MAXN],c[MAXN];int f[MAXN][MAXN],i,j;//f[i][v]表示第i件物品放入容量為v的背包所能產生的最大價值。 int maxn(int x,int y)//比較,輸出最大值 {if(x>y)return x;else return y;
}int main()
{
cin>>m>>n; for(i=1;i<=n;i++)
cin>>w[i]>>c[i];//輸入不解釋 for(i=1;i<=n;i++)for(j=m;j>0;j--)
{if(w[i]<=j)
f[i][j]=maxn(f[i-1][j],f[i-1][j-w[i]]+c[i]);//狀態轉移方程式。 else f[i][j]=f[i-1][j];
}
cout<<f[n][m];return 0;
}

好了以上就是最簡單的01背包模板了qwq。

【二:完全背包問題】

還是例題打頭陣。

完全背包問題

【題目描述】

設有n種物品,每種物品有一個價值,但每種物品的數量是無限的,同時有一個背包,最大承載量微m,今從n種物品中選取若干件,(同一種物品可以多次選舉)使其重量的和小于等于m,而且價值的和最大。

【輸入】共N+1行

第一行:兩個整數:M(背包容量M<=200)和N(物品數量,N<=30);

第二行至第N+1行,每行兩個整數,Wi,Ci,表示每個物品的重量和價值。

【輸出】

近一行:一個數,表示最大的價值;

【輸入樣例】

10 4

2 1

3 3

4 5

7 9

【輸出樣例】

12

有的小伙伴們可能一看到例題就會發現一個與01背包不同的地方:每種物品的數量是無限多的。沒錯,這就是完全背包問題。其實這個問題沒有比01背包難多少,只是不是很好想。

既然每種物品所取的數量可能是1,2,3.......,所以與它相關的策略便不是取或者不取的問題了,而是,取不取,取多少的問題了。既然同樣是背包問題,那么我們可不可以考慮延續01背包的方法來做呢,答案是Yes。其實與01背包不同的地方就是只有放進去的每種物品的件數不一定是1就是了,那么只要多一重關于每種物品取多少的循環不就可以了嗎。相對的,其狀態轉移方程式也要略有改動,變為:f[i][v]=max(f[i-1][v-k*w[i]]+k*c[i],f[i-1][v]),可見就是比01背包多了一個k而已,而這個k就是循環的這第i種物品取的件數。

現在解釋一下原因:首先我們想一下為甚么在上題中的01背包代碼中第二重循環是for(int j=m;j>=0;j--)而不是for(int j=1;j~~~)

Because~因為:要保證第i次循環里的狀態f[i][v]是由狀態f[i][[v-w[i]]遞推而來的,也就是為了保證每件物品只選一次,保證在考慮“選入第i件物品”這件策略時,依據的是一個絕不可能選入第i種物品的子結果f[i][v-w[i]]。如果如果還不是很明白,大家可以畫一個表格來自己推一下,看看逆序和正序時得到的結果有什么不同。。。。。。

好了重點來了!!?: 現在大家已經知道了01背包的順序,那么現在問題來了:完全背包的順序呢??

考慮“加選一件第i種物品”這種策略時,卻正需要一個可能已經選入第i種物品的子結果f[i][v=w[i]],所以就可以并且必須采用v=0,.....v的順序循環,這就是則個簡單的程序何以成立的原因啦。

然后給大家附上代碼:: ? ?//不準抄襲!!? ? ?好吧像我這種蒟蒻代碼有誰會抄呢 呵呵~~

#include
#includeusing namespace std;const int MAXN=31,MAXM=201;int m,n,w[MAXN],c[MAXN],f[MAXN][MAXM];int main()
{scanf("%d%d",&m,&n);for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]);for(int i=1;i<=n;i++)for(int v=1;v<=m;v++)if(v1][v];else {if(f[i-1][v]>f[i][v-w[i]]+c[i]) f[i][v]=f[i-1][v];else f[i][v]=f[i][v-w[i]]+c[i];}
printf("%d",f[n][m]); return 0;
}//這個碼風不是很好看,大家看不慣可以改一改......

?【三:多重背包問題】

好了依然是看例題::

模板例題:慶功會

【題目描述】

設有n種物品,每種物品有一個價值,但每種物品的數量是有限的,同時有一個背包,最大承載量微m,今從n種物品中選取若干件,(同一種物品可以多次選舉)使其重量的和小于等于m,而且價值的和最大。

【輸入】共N+1行

第一行:兩個整數:N(物品數量,N<=30)和M(背包容量M<=200)

第二行至第N+1行,每行兩個整數,Wi,Ci,Si,分別表示每個物品的重量、價值、數量。

【輸出】

近一行:一個數,表示最大的價值;

【輸入樣例】

5 1000

80 20 4

40 50 9

30 50 7

40 30 6

20 20 1

【輸出樣例】

1040

  這個題目就又不一樣了,因為題目中說的每一件物品的件數是“有限的”,也就是說可以是1、2......但也不是無限。

這個看起來可能就比較e xin,但是如果仔細想一想,其實也并不是很難。

(蒟蒻認為的)重點詳解:
做法1:和完全背包接軌:完全背包里面有一個k,用來表示物品的個數,這里面也是一樣的,因為對于第i種物品,我們可以設置他有n[i]+1種取數策略,:取0、1.....n[i]件,so我們再次設置一個f[i][v]表示前i種物品放入一個容量為v的背包所能產生的最大價值,那么:f[i][v]=max(f[i-1)[v-k*w[i]]+k*c[i],f[i-1][v]),那么復雜度就是O(V*Σn[i])。

? ?顯然,上方做法時間復雜度太高。于是就有了第二個方法。

做法2:和01背包接軌。大家可能都覺得完全背包比01背包更要高大上一些,但是很不幸,做法2是要遠遠優于做法1的。先給大家一個引路思想,第i件物品有n[i]的數量,那么是不是可以把它轉化為n個數量只有一個的物品呢??看到這里,你恍然大悟:哦,好巧妙。

而事實上,如果你只想到這里,就開始興奮無腦地開始打代碼的話,你就會呵呵進化成神犇了。。。。。你您可以算一算如果這樣做的話時間復雜度是多少:O(V*Σn[i]) ?............

好極了,可是我并沒有在逗你啊。。。。。

那么接下來就是優化了,在這里,我們考慮二進制優化。

方法:將第i件物品分成若干件物品,每個物品有一個系數l,這件物品的費用和價值軍事原來的費用和價值乘以l,使這些系數分別為1,2,4...2(k-1)余出來的再拿出來就是n[i]-2(k+1),且k是滿足n[i]-2(k+1)>0的最大整數。(例:13分為1,2,4,6)。

這樣就將第i件物品分成了O(logn[i)種物品,將時間復雜度降低成為了O(V*Σlogn[i])的01背包問題,改進是不是很大呢?

下面是代碼:

#include
#include#define MAXN 10001#define MAXM 6001using namespace std;int v[MAXN],w[MAXN],f[MAXM];int n,m,n1;int max(int a,int b)
{if(a>b) return a;else return b;
}int main()
{
scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)
{int x,y,s,t=1;
scanf("%d%d%d",&x,&y,&s);while(s>=t)
{
v[++n1]=x*t;
w[n1]=y*t;
s-=t;
t*=2;
}
v[++n1]=x*s;
w[n1]=y*s;
}for(int i=1;i<=n1;i++)for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
printf("%d\n",f[m]); return 0;
}

【四:混合三種背包問題】

  大概很多人一看到這個就淚奔了,對,沒錯,就是把01、完全、多重背包混合起來考你。你可能肯定覺得很惡心,覺得難極了,確實,對于沒有學過前幾種背包的人來說,這是一個很大的挑戰,但是不要忘了,我們已經學完了呀!所以,我哦們就可以很輕易地將這一個難題轉化為極個簡單的子題了!!

  其實也不用怎么解釋了,先判斷該物品是不是屬于完全背包,if(YES)->用完全背包去做,if(NOT)->用混合背包去做(因為01背包本身即是多重背包的一個樣例,用多重背包做完全沒有問題的。)

  好了下面附上代碼:

#include
#includeusing namespace std;int m,n,w[31],c[31],p[31],f[201];int max(int a,int b)
{if(a>b) return a;else return b;
}int main()
{
scanf("%d%d",&m,&n);for(int i=1;i<=n;i++)
scanf("%d%d%d",&w[i],&c[i],&p[i]);for(int i=1;i<=n;i++)if(p[i]==0)
{for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
}else
{for(int j=1;j

)

for(int k=m;k>=w[i];k--)
f[k]=max(f[k],f[k-w[i]]+c[i]);
}
printf("%d",f[m]);return 0;
}

【五:二維費用的背包】

  這又是一種新的背包問題了,顯而易見,他的費用是二維的。什么叫二維的呢?先來看一道例題,你就能明白了。

? ? ? ? ? ? ? ? ? ??? ? ?例題:潛水員

【問題描述】

潛水員為了潛水要使用特殊的裝備,他有一個帶2種氣體的氣缸,一個為氧氣,一個為氮氣,讓錢會員下潛的深度需要各種數量的氧和氮,潛水員有一定數量的氣缸,每個氣缸都有重量和氣體容量,潛水員為了完成她的工作需要特定的數量的氧和氮,他完成工作需要氣缸的總重的最低限度是多少??

【輸入格式】

第一行:兩個整數,m,n,(1<=m<=21,1<=n<=79)。他們表示氧,氮各自需要的量。

第二行:為整數k(1<=k<=1000)表示氣缸的個數。

此后的k行每行包括一個ai,bi,ci,(1<=ai<=21,1<=bi<=79,c<=ci<=800)三個整數,分別表示第i個氣缸里的氧的容量,氮的容量,以及氣缸重量。

【輸出格式】

僅一行,包含一個整數,為重量和的最低值。

【輸入樣例】

5 60

5

3 36 120

10 25 129

5 50 250

1 45 130

4 20 119

【輸出樣例】

249

好的,我覺得大多數人可能都已經明白了什么叫二維了,在這個例題中,每一個氣缸油兩種不同的費用,選擇這件物品必須同時付出這兩種代價,對于每一種代價有一個背包容量,問怎么樣選擇物品可以得到最大的價值。

接下來不只針對例題,而是對于大多數二維背包題:

  我們可以定義第i種物品的代價分別為a[i]和b[i],兩種背包容量分別為V和U,第i件物品的價值為c[i]。

那么顯而易見,我們的算法需要增加一維,那么就將我們的f再增加一維即可,那么就有了狀態轉移方程式::

f[i][v][u]=max)f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+c[i]),當然,當物品只取一次是的時候變量v和u采取逆序循環。

但有的時候,很多良心的題經常是將二維背包以一種有一點隱晦的方式表示出來,例如:最多只能取M件物品,此時就又多了一個“件數”的費用,設f[v][m]表示付出費用v,最多選m件的時候可以得到的最大收入。之后便可以針對01、完全、多重背包采用不同的方式進行運算了。最后,在f[0 -> V][1 -> M]范圍內尋找答案。

然后,附上【潛水員】例題的代碼。

#include
#include
#include#define MAXN 1001#define MAXM 101using namespace std;int v,u,k;int a[MAXN],b[MAXN],c[MAXN];int f[MAXM][MAXM];int main()
{
memset(f,127,sizeof(f));
f[0][0]=0;
scanf("%d%d%d",&v,&u,&k);for(int i=1;i<=k;i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]);for(int i=1;i<=k;i++)for(int j=v;j>=0;j--)for(int l=u;l>=0;l--)
{ int t1=j+a[i],t2=l+b[i];;if(t1>v) t1=v;if(t2>u) t2=u;if(f[t1][t2]>f[j][l]+c[i]) f[t1][t2]=f[j][l]+c[i];
}
printf("%d",f[v][u]);return 0;
}

好了,關于背包問題就先說到這里(持續更新。。。),如果有不明白個或者錯誤的地方可以給我留言。。。

標簽:?背包

2

總結

以上是生活随笔為你收集整理的c++ 多重背包状态转移方程_【模板】各种背包问题amp;讲解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久精品999 | 成人av网址在线 | xvideos成人免费视频 | 久久久国产精品黄毛片 | 国产成人午夜精华液 | 五月亚洲综合 | 综合视频在线观看 | 裸体男女树林做爰 | 欧美亚洲综合久久 | 人人澡人人爱 | 日韩啪 | 黄色香蕉视频 | 亚洲欧美精品午睡沙发 | 免费色视频| 欧美日韩中文一区 | 国产一区二区精品在线观看 | 国产精品久久久久久久久绿色 | 手机看片日韩欧美 | 超碰com| 亚洲精品一区二三区不卡 | 亚洲三区在线播放 | 亚洲精品视频在线播放 | 亚洲黄站 | 国产又大又硬又粗 | 色爱五月天 | 一区二区三区四区五区在线视频 | 欧美精品1 | 夜夜高潮夜夜爽 | 我爱52av| 免费特级毛片 | 亚洲国产123 | 亚洲日本视频 | 三度诱惑免费版电影在线观看 | 欧美午夜性生活 | 中文字幕在线观看网站 | 污污网站免费在线观看 | 中文字幕日韩精品在线观看 | 美日韩免费视频 | 亚洲国产精品综合 | 国产精品自慰网站 | 国产麻豆精品久久一二三 | 好吊妞在线观看 | www.99爱| 亚洲欧美高清 | 久久乐国产精品 | 国语对白少妇spa私密按摩 | 97爱视频 | 欧洲国产精品 | 亚洲欧洲国产日韩 | 在线免费观看污片 | 在线色综合 | 七月婷婷综合 | 免费看91 | 九色蝌蚪视频 | 中文字幕日韩在线观看 | 国产每日更新 | 日本xxxx高潮少妇 | 黄色亚洲网站 | 亚洲欧美自拍另类 | 欧美一区二区三区激情 | 久久久精品在线 | 成人做爰69片免费观看 | 欧亚毛片 | 久插网| 区一区二视频 | 性爽爽| 国产成人精品二区三区亚瑟 | 国产主播av| 九一av| 成人欧美一区二区三区 | 免费人成在线观看视频播放 | 欧美视频在线免费看 | www.99色 | 成人免费不卡视频 | 中文字幕精品一区二区三区视频 | 久久久精品人妻无码专区 | 大尺度做爰呻吟舌吻网站 | www,av在线 | 欧美一级免费黄色片 | 激情开心网站 | 亚洲 欧美 综合 | 日本综合色 | 成人免费观看在线视频 | 欧美另类色 | 精品一区二区在线观看视频 | 九色视频在线播放 | 色吊丝中文字幕 | 国产亚洲精品网站 | 黄色网址链接 | 日日日夜夜操 | kendra lust free xxx | 精品久久久蜜桃 | 日韩欧美视频一区二区三区 | 亚洲色图28p | 少妇久久久久久被弄到高潮 | 欧美性一区二区 | 国产乱论| 欧美一区二区免费电影 | 2019中文字幕在线视频 |