【动态规划】三种基本背包问题
動態(tài)規(guī)劃?是對解最優(yōu)化問題的一種途徑 它往往是針對一種最優(yōu)化問題 根據(jù)問題的不同性質(zhì) 確定不同的設(shè)計方法?
因為這篇文章我想說點關(guān)于背包問題的事情 所以不再過多介紹動態(tài)規(guī)劃?
背包問題?是動態(tài)規(guī)劃中的一個經(jīng)典題型 在聯(lián)賽中也經(jīng)常出現(xiàn) 其基本問題主要分為01 完全 多重 三種?
下面就通過程序與例題分別來說一下三種基本問題
01背包
有n件物品和容量為m的背包 給出i件物品的重量以及價值 求解讓裝入背包的物品重量不超過背包容量 且價值最大?
特點?這是最簡單的背包問題 特點是每個物品只有一件供你選擇放還是不放
對于這個問題一般有兩種解法 下面分別來介紹一下
① 二維解法?
設(shè)f[i][j]表示前i件物品 總重量不超過j的最大價值 可得出狀態(tài)轉(zhuǎn)移方程?
f[i][j]=max{f[i-1][j-a[i]]+b[i],f[i-1][j]}?
或許到這里大家對這個方程還不是那么熟悉,我們便通過一個實例來走一遍:
物品件數(shù)n=4,背包容量m=8
| w(體積) | 2 | 3 | 4 | 5 |
| v(價值) | 3 | 4 | 5 | 6 |
初始化:?
?
總表:?
現(xiàn)在挑幾個典型的說一下這個表是怎么更新的:?
點(i=2,j=3):這時有兩個物品可以放入,背包容量為3,此時我們面臨一個抉擇,放還是不放第二件物品,我們看一下,上一狀態(tài),也就是只有一件物品或者說我們不放這件物品時的最大價值(i=1,j=3)為3,再看一下如果我們放這件物品的最大價值,(此時空間明顯不足以同時放入這兩件物品,我們?nèi)绻胚@件物品總得給它留出足夠的空間吧,所以我們計算一下當給他留出足夠空間時,空間還剩多少,此時背包的最大價值是多少)(i=1,j=3-3=0)為0(也就是說此時我如果想放入第二件物品的話,就得把第一件物品拿出來,拿出來后背包價值是0),再把第二件物品放進去,此時背包價值為4,我們比較一下這兩個狀態(tài),如果不放第二件物品背包價值為3,放第二件物品背包價值為4,我們當然選擇翻入第二件物品。?
如果這個點還是不太明白我們再試一個點,算法是一樣的?
點(i=3,j=7):這時有三個物品可以放入,背包容量為7,我們面臨一個抉擇,放還是不放第三個物品,
我們看一下,上一狀態(tài),也就是只有一件物品或者說我們不放這件物品時的最大價值(i=2,j=7)為7,再看一下如果我們放這件物品的最大價值,(此時空間明顯不足以同時放入這兩件物品,我們?nèi)绻胚@件物品總得給它留出足夠的空間吧,所以我們計算一下當給他留出足夠空間時,空間還剩多少,此時背包的最大價值是多少)(i=2,j=7-4=3)為4((重點理解!!!)也就是說要想放入第三個物品得給給他讓出v[3]=4的容量,此時背包容量還剩3,我們可以知道,背包容量為3時背包最大價值為(i=2,j=3)=4),再把第三件物品放進去,此時背包價值為4+5=9,我們比較一下這兩個狀態(tài),如果不放第三件物品背包價值為7,放第二件物品背包價值為9,我們當然選擇翻入第三件物品。
代碼如下
#include<iostream> using namespace std; int main() {int m,n;cin>>n>>m;int a[50001],b[50001];int f[5001][5001];for(int i=1;i<=n;i++)cin>>a[i]>>b[i];for(int i=1;i<=n;i++)for(int j=m;j>0;j--){if(a[i]<=j)f[i][j]=max(f[i-1][j],f[i-1][j-a[i]]+b[i]);else f[i][j]=f[i-1][j];}cout<<f[n][m]<<endl; //最優(yōu)解//COYG }雖然“原理”沒有錯 但是f數(shù)組開的太大 (一般應(yīng)該5000就頂頭了)?
在一些情況下 題目的數(shù)據(jù)會很大 因此f數(shù)組不開到一定程度是沒有辦法ac的 那么該怎么辦呢 于是
②一維解法?
設(shè)f[j]表示重量不超過j公斤的最大價值 可得出狀態(tài)轉(zhuǎn)移方程?
fj=maxj{fj,f[j?a[i]]+b[i]}fj=maxj{fj,f[j?a[i]]+b[i]}
代碼如下
?
#include<iostream> using namespace std; int main() {int n,m;cin>>n>>m;int a[50001],b[50001]; for(int i=1;i<=n;i++)cin>>a[i]>>b[i];int f[50001]={0};for(int i=1;i<=n;i++){ for(int j=m;j>=a[i];j--)if(f[j-a[i]]+b[i]>f[j])f[j]=f[j-a[i]]+b[i]; }cout<<f[m]<<endl; //最優(yōu)解//COYG }這樣用一維數(shù)組代替二維數(shù)組就解決了很多問題 所以用一維數(shù)組解決01背包是很重要的
01背包的例題有:[USACO07DEC]手鏈Charm Bracelet(洛谷搜索 P2871) 采藥(洛谷搜索 P1048) [Noip普及組2001]裝箱問題(洛谷搜索 P1049)
完全背包
有n件物品和容量為m的背包 給出i件物品的重量以及價值 求解讓裝入背包的物品重量不超過背包容量 且價值最大?
特點?題干看似與01一樣 但它的特點是每個物品可以無限選用
其實這個題也可以寫二維和一維兩種 但之前已經(jīng)說過了二維的有一定局限 所以在此之介紹一維?
一維?
設(shè)f[j]表示重量不超過j公斤的最大價值 可得出狀態(tài)轉(zhuǎn)移方程?
fj=maxj{fj,f[j?a[i]]+b[i]}fj=maxj{fj,f[j?a[i]]+b[i]}
代碼如下
?
#include<iostream> using namespace std; int main() {int n,m;cin>>n>>m;int a[50001],b[50001];int f[50001]={0};for(int i=1;i<=n;i++){cin>>a[i]>>b[i];}for(int i=1;i<=n;i++)for(int j=a[i];j<=m;j++){if(f[j-a[i]]+b[i]>f[j])f[j]=f[j-a[i]]+b[i];}cout<<f[m]<<endl;//最優(yōu)解//COYG }大家有沒有感覺代碼很熟悉?每錯 一維完全背包的代碼與一維01背包的代碼只在循環(huán)上有些差別 而且狀態(tài)轉(zhuǎn)移方程也一樣
例題可以百度搜索收益(也叫投資)?
算了好人做到底我還是ctrl+v一下題目吧?
【題目描述】收益 (POJ 2063)?
“建太空梯進入太空要1兆億?”魔法學(xué)院的院長瞪大了眼睛。?
“這只是基礎(chǔ)設(shè)施的費用,后期還要……”墨老師掰著手指算。?
“哎呀,現(xiàn)在地主也很窮啊,學(xué)院的錢批下來就這么多,你想辦法用這筆錢在債券市場上獲得最大收益吧。”院長皺著眉頭。?
簡單來說,就是你有一筆錢,你要將這筆錢去投資債券,現(xiàn)在有d種債券,每種債券都有一個價值和年收益,債券的價值是1000的倍數(shù),問你如何投資在n年后的獲得最大收益。?
【輸入格式】?
第一個為一個整數(shù)M,表示有M組數(shù)據(jù)。?
每組數(shù)據(jù)第一行有兩個整數(shù),表示初始資金(不超過50000)和年數(shù)n。?
每組數(shù)據(jù)第二行為一個整數(shù)d(1 ≤ d≤10),表示債券種類。?
隨后d行每行有兩個整數(shù),表示該債券的價值和年收益。年收益不會超過債券價值的10%。?
所有數(shù)據(jù)不超過整型取值范圍。?
【輸出格式】?
每組數(shù)據(jù),輸出n年后獲得的最大收益。?
【輸入樣例】?
1?
10000 4?
2?
4000 400?
3000 250?
【輸出樣例】?
14050
貼一下我這個題的代碼
#include<iostream> #include<cstring> using namespace std; int main() {int m,y,n,d,ans=0,a[100001],b[100001];int f[100001]={0}; cin>>m;while(m--){cin>>y>>n;cin>>d;for(int i=1;i<=d;i++){cin>>a[i]>>b[i];}for(int o=1;o<=n;o++){for(int i=1;i<=d;i++)for(int j=a[i];j<=y;j++){f[j]=max(f[j-a[i]]+b[i],f[j]);}y+=f[y]; //每次都要累計memset(f,0,sizeof(f));}cout<<y<<endl;}return 0; } //小蒟蒻代碼丑 //COYG多重背包
有n件物品和容量為m的背包 給出i件物品的重量以及價值 還有數(shù)量 求解讓裝入背包的物品重量不超過背包容量 且價值最大?
特點?它與完全背包有類似點 特點是每個物品都有了一定的數(shù)量
狀態(tài)轉(zhuǎn)移方程為:?
f[j]=max{f[j],f[j?k?a[i]]+k?b[i]}f[j]=max{f[j],f[j?k?a[i]]+k?b[i]}
【輸入樣例】?
8 2?
2 100 4?
4 100 2?
【輸出樣例】?
400
?
代碼如下
#include<iostream>using namespace std; int main() {int m,n;cin>>m>>n;int a[10001],b[10001],c[10001];for(int i=1;i<=n;i++){cin>>a[i]>>b[i]>>c[i];}int f[10001];for(int i=1;i<=n;i++)for(int j=m;j>=0;j--)for(int k=0;k<=c[i];k++){if(j-k*a[i]<0)break;f[j]=max(f[j],f[j-k*a[i]]+k*b[i]);}cout<<f[m]<<endl;//最優(yōu)解 }總結(jié)
以上是生活随笔為你收集整理的【动态规划】三种基本背包问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zcmu1156(树状数组)
- 下一篇: kibana客户端工具操作Elastic