動態規劃之0-1揹包問題
阿新 • • 發佈:2018-12-19
問題:
物品集合s={1,2,3,4,…,n},物品i的重量為wi,其價值為vi,揹包的容量(最大載重量)為W,如何裝使物品價值最大。(物品不能分割)
分析:
p(i,j)是揹包容量為j,可選物品為i(i+1,…,n)時的最優解 (“將前i個物品放入容量為j的揹包中”轉化為只考慮物品i)
- p(i,j)=p(i+1,j)表示沒裝入第i個物品或者第i個物品的重量wi超過揹包容量j。
- p(i,j)=p(i+1,j-wi)+vi表示裝入物品i,價值增加vi,揹包容量變為j-wi。
- 最後一個物品p(n,j),j大於wn,則能裝入,價值增加vn,否則不能裝入,價值增加0。
程式碼:
最優值:
#include<bits/stdc++.h> using namespace std; #define num 100//物品數量 #define num1 1000//揹包容量 int w[num];//物品重量 int v[num];//物品價值 int p[num][num1];//遞迴陣列 void value(int c,int n){//c表示揹包容量W,n是物品數量 //邊界 int jMax=min(w[n]-1,c); //先將小的不可以裝的置為0,將大於w[n]可以裝的置為v[n] for(int j=0;j<=jMAx;j++){ p[n][j]=0; } for(int j=w[n];j<=c;j++){ p[n][j]=v[n]; } //計算遞推式 for(int i=n-1;i>1;i--){ jMax=min(w[i]-1,c); for(int j=0;j<=jMax;j++){ p[i][j]=p[i+1][j]; } for(int j=w[i];j<=c;j++){ p[i][j]=max(p[i+1][j],p[i+1][j-w[i]+v[i]); } } p[1][c]=p[2][c]; if(c>=w[1]){ p[1][c]=max(p[1][c],p[2][c-w[1]+v[1]); } }
最優解:
//用xi=0或1表示物品i裝入或不裝入揹包
void jie(int c,int n,int x[]){
for(int i=1;i<n;i++){
if(p[i][c]==p[i+1][c]){
x[i]=0;
}
else{
x[i]=1;
c=c-w[i];
}
x[n]=(p[n][c])?1:0;
}
}
主函式:
int main(){ int x[num]; int W; cin>>W; int n; cin>>n; for(int i=1;i<=n;i++){ cin>>w[i]>>v[i]; } memset(p,0,sizeof(p)); value(W,n); cout<<p[1][W]<<endl; jie(W,n,x); for(int i=1;i<=n;i++){ if(x[i]){ cout<<i<<endl; } } return 0; }