推荐一篇好文章:http://blog.csdn.net/sj13051180/article/details/6687674
0-1背包,每件物品只有一个,对于每件物品只有取与不取两种情况,
完全背包,每件物品无数多个,对于每件物品可以取任意多个。
多重背包,每件物品有限多个,对于每件物品可以取任意多个。
以poj-3624与poj-1276为原型,阐释三种背包的代码。
0-1背包:
#include <iostream> #include <stdio.h> using namespace std; int main(){ int dp[12900]; int n,m; int v[3405]; int w[3405]; while(cin >> n >> m){ for(int j=0;j<=m;j++) dp[j]=0; for(int i=1;i<=n;i++) cin >> w[i] >> v[i]; for(int i=1;i<=n;i++) for(int j=m;j>=w[i];j--) dp[j] = max(dp[j],dp[j-w[i]]+v[i]); for(int j=0;j<=m;j++){ cout << dp[j] <<" "; } cout <<endl; cout << dp[m] <<endl; } return 0; }
完全背包:
#include <iostream> #include <stdio.h> using namespace std; int main(){ int dp[12900]; int n,m; int v[3405]; int w[3405]; int num[3405]; while(cin >> n >> m){ for(int j=0;j<=m;j++) dp[j]=0; for(int i=1;i<=n;i++) cin >> w[i] >> v[i] ; for(int i=1;i<=n;i++) for(int k=1;k<=m/w[i];k++) for(int j=k*w[i];j<=m;j++) dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]); for(int j=0;j<=m;j++){ cout << dp[j] <<" "; } cout <<endl; cout << dp[m] <<endl; } return 0; }
多重背包:
三重循环,二维数组暴力解法(超时,超空间)
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; int dp[1406][1090]; int main(){ int n,m; int v[3405]; int w[3405]; int num[3405]; while(cin >> n >> m){ memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) cin >> w[i] >> v[i] >>num[i]; for(int i=1;i<=n;i++) for(int k=1;k<=num[i];k++) for(int j=m;j>=k*w[i];j--) dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*w[i]]+k*v[i]); for(int i=0;i<=n;i++){ for(int j=0;j<=m;j++){ cout << dp[i][j] << " "; } cout << endl; } cout << dp[n][m] <<endl; } return 0; }
三重循环,一位数组(超时)
实现时,用临时的一维数组暂存i-1层物品的价值。
#include <string.h> #include <iostream> #include <stdio.h> using namespace std; int main(){ int dp[12900]; int temp[12900]; int n,m; int v[3405]; int w[3405]; int num[3405]; while(cin >> n >> m){ memset(dp,0,sizeof(dp)); memset(temp,0,sizeof(temp)); for(int i=1;i<=n;i++) cin >> w[i] >> v[i] >>num[i]; for(int i=1;i<=n;i++){ for(int j=0;j<=m;j++){ cout << dp[j] <<" "; } cout << endl; for(int i=0;i<=m;i++) temp[i]=dp[i]; for(int k=1;k<=num[i];k++){ for(int j=m;j>=k*w[i];j--){ dp[j]=max(dp[j],temp[j-k*w[i]]+k*v[i]); } } } for(int j=0;j<=m;j++){ cout << dp[j] <<" "; } cout << endl; cout << dp[m] <<endl; } return 0; } /* 3 5 1 60 2 2 100 2 3 120 2 0 0 0 0 0 0 0 60 120 120 120 120 0 60 120 160 220 260 0 60 120 160 220 260 260 */
双重循环,一位数组(省时省空间)
二进制压缩,把多数量的每种物品划分成单数量的多种物品,再运用0-1背包求解。
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; int dp[100005]; int w[1000]; int main(){ int n,m,a,b,cnt; while(cin >> n >> m){ cnt=0; memset(dp,0,sizeof(dp)); memset(w,0,sizeof(w)); for(int i=1;i<=m;i++){ cin >> a >> b; for(int j=1;j<=a;j*=2){ w[++cnt]=j*b; a-=j; } if(a>0){ w[++cnt]=a*b; } } for(int i=1;i<=cnt;i++) for(int j=n;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+w[i]); cout << dp[n] <<endl; } return 0; }