背包问题
acm入门算法--简单背包问题
01背包问题
问题描述:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。
0-1背包问题
Time Limit: 1 Second(s) Memory Limit: 32 MB
Total Submission(s): 1172 Accepted Submission(s): 456
Problem Description
给定n种物品和1个背包,物品i的重量是wi,其价值为vi,背包的容量为C。要求选择装入背包的物品,使得装入背包中物品的总价值最大。
Input
每组测试数据包含3行,第1行为n和c,表示有n(0<=n<=400)个物品且背包容量为c (c<=1500),第二行为这n个物品的重量wi(1<=wi<=1000),第三行为这n个物品的价值vi。背包容量和物品重量都为整数。
Output
输出装入背包的最大总价值,每个答案一行。
Sample Input
5 10
2 2 6 5 4
6 3 5 4 6
Sample Output
15
算法思想:背包问题是典型的动态规划问题,给定一个背包和这个背包的承重量,怎么放才能使背包实现物品的最大价值。
01背包问题的特点是:每种物品仅有一件,可以选择放或不放。(所以说是最基础的,后面还会有完全背包,多重背包,就不局限在一件,也可以有更多选择)。
接下来我们来确认状态转移方程:
每一件物品都有两种选择,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果第i件物品重量不超过背包的承重量(超重肯定不能放),
我们选择不把第i件物品放入背包中,此时背包实现的最大价值就等同于前i-1件物品在同等容量背包中实现的最大价值f[i-1][c];
如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为c-w[i]的背包中”,此时能获得的最大价值就是f [i-1][c-w[i]]再加上通过放入第i件物品获得的价值v[i]。
设f[i][j]为第i件物品放入背包容量为j的背包中实现的最大价值,不难得出状态转移方程为:
f[i][j]=max{f[i-1][c], f[i-1][c-w[i]]+v[i]}
下面贴出代码:
#include<iostream.h> #include<string.h> int f[402][1502],w[402],v[402]; int max(int a,int b) { return a>b?a:b; } int KnapSack(int n,int c,int w[],int v[]) { int i,j; memset(f,0,sizeof(f)); for(i=1;i<=n;i++) { for(j=1;j<=c;j++) { if(j<w[i-1])//物品重量超过背包容量 f[i][j]=f[i-1][j]; else//选择放或不放的最优策略 f[i][j]=max(f[i-1][j],f[i-1][j-w[i-1]]+v[i-1]); } } return f[n][c]; } int main() { int n,c; while(cin>>n>>c) { int i; for(i=0;i<n;i++) cin>>w[i]; for(i=0;i<n;i++) cin>>v[i]; int maxv=KnapSack(n,c,w,v); cout<<maxv<<endl; } return 0; }
二维背包问题
问题描述:大体与01背包相似,只是多了个限制条件,01背包会了,这个也不难
二维费用背包问题
Time Limit: 1 Second(s) Memory Limit: 32 MB
Total Submission(s): 91 Accepted Submission(s): 49
Problem Description
给定N种物品和1个背包,物品i的体积是ai,重量是bi, 价值为vi,背包的体积为V,背包的最大承载重量W。要求选择装入背包的物品,使得装入背包中物品的总价值最大。
Input
每组测试数据包含4行,第1行为N,V,W,表示有N个物品且背包体积为V和载重量W,第2行为这N个物品的体积ai,第3行为这N个物品的重量bi,第4行为这N个物品的价值vi。
所有输入数字都为整数,范围大于0,小于等于100。处理到文件结束。
Output
输出装入背包的最大总价值,每个答案一行。
Sample Input
4 3 1
1 1 1 2
2 2 1 1
3 3 1 3
Sample Output
3
算法思想:状态转移方程同01背包类似,多了体积这个限制,如果第i件物品放入背包中问题就转化为“前i-1件物品放入剩下的承重量为c-w[i],体积为v-a[i]的背包”,
此时能获得的最大价值就是f [i-1][c-w[i]][v-a[i]]再加上通过放入第i件物品获得的价值v[i]。
设f[i][j][k]为第i件物品放入背包容量为j,体积为k的背包中实现的最大价值,不难得出状态转移方程为:
f[i][j][k]=max{f[i-1][c][v], f[i-1][c-w[i]][v-a[i]]+v[i]}
代码如下:
#include<iostream> #include<string> using namespace std; int a[100],v[100],w[100],f[100][100][100]; int maxV(int v1,int v2){ return v1>v2?v1:v2; } int main(){ int N,V,W; while(cin>>N>>V>>W){ int i,j,k; memset(f,0,sizeof(f)); for(i=0;i<N;i++)cin>>a[i]; for(i=0;i<N;i++)cin>>w[i]; for(i=0;i<N;i++)cin>>v[i]; for(i=0;i<N;i++){ for(j=0;j<=V;j++){ for(k=0;k<=W;k++){ if(i==0){//第一件物品 if(a[i]<=j&&w[i]<=k)//满足背包条件限制 f[i][j][k]=v[i];//最大实现价值为当前物品价值 } else{ if(a[i]>j||w[i]>k) f[i][j][k]=f[i-1][j][k]; else f[i][j][k]=maxV(f[i-1][j][k],f[i-1][j-a[i]][k-w[i]]+v[i]); } } } } cout<<f[N-1][V][W]<<endl; } return 0; }