问题描述:
给定n种物品和一个背包,物品i的重量是Wi,其价值为Vi,设计一个动态规划算法选择装入背包的物品,使得装入背包的物品的总价值最大。在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入物品i的一部分。要求如下:
(1)输入:要求可以由用户输入物品的个数、物品的重量和相应的价值,以及背包的总容量。
(2)输出:背包的总价值,以及哪几个物品放入了背包。
算法思路
首先,0-1问题具有最优子结构,即,设(y1,y2,…,yn)yi∈{0,1}(0表示不选,1表示选)是0-1背包问题的一个最优解,则(y2,y3,…,yn)是子问题
的一个最优解。
设m(i,j)是,背包容量为j,可选择物品为第i,i+1,…,n个物品时0-1背包问题的最优值,例如:m(3,10),表示,背包容量为10,可以选择的物品为第3到第n个,使得选择的物品价值最大。所以,m(1,j)为背包问题的解.
分析:
1、如果第i个物品的重量大于背包的容量,则第i个物品不装进背包,即
m(i,j)=m(i+1,j)
- 1
2、如果第i个物品的重量小于背包的容量,则会有以下两种情况:
(a)如果把第i个物品装入背包,则背包中物品的价值=m(i+1,j-w[i])+v[i]
(b)如果第i个物品没有装入背包,则背包中物品价值=m(i+1,j)
取二者中价值最大的作为最优解。
max(m(i+1,j), m(i+1,j-w[i])+v[i])
- 1
边界条件:
当j=0时,即背包容量为0,则m(i,j)=0;
当i=n时,即只能选择第n个物品,如果w[i] <= j ,即背包能装下最第n个物品,则m(i,j)=v[n],否则,m(i,j)=0;
综上,
动态规划算法求解过程:
初始:m[i][0]=0,i=1,2,……,n
计算m[n,j],j=1,2,……,c (c为背包容量)
第1步:计算m[n-1,j],j=1,2,……,c
第2步:计算m[n-2,j],j=1,2,……,c
……
第i步: 计算m[n-i,j],j=1,2,……,c
……
第n-2步:计算m[2,j],j=1,2,……,c
第n-1步:计算m[1,j],j=1,2,……,c
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
具体算法:
#include""
#include""
#include""
int max(int x,int y){
int retValue = x>y?x:y;
return retValue;
}
void knapsack(int n,int c,int *w,int *v,int **m){
int i,j;
//当背包重量为0时,c[i][0]=0;
for(i=0;i<=n;i++)
m[i][0]=0;
//边界条件:只有第n个物体,背包容量分别为1,2,…,c的时候m的值
for(j=1;j<=c;j++)
if(j>=w[n])
m[n][j]=v[n];
else
m[n][j]=0;
//依次求解m[i][j],1<=i<n,1<=j<=c
for(i=n-1;i>=1;i--)
for(j=1;j<=c;j++)
if(j<w[i])
m[i][j]=m[i+1][j];
else
m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
printf("MaxValue=%d\n",m[1][c]);
}
//具体选了哪些物品
void traceback(int **m ,int *w, int c, int n, int *x){
//求x[i],从m[1][c]开始
int j=c,i;
for(i=1;i<n;i++){
if(m[i][j]==m[i+1][j])//没有物品增加
x[i]=0;
else{
x[i]=1;
j=j-w[i];
}
}
if (m[i][j]>0)
x[n]=1;
else
x[n]=0;
}
int main(){
int n;//nums of goods
int c;//capacity
scanf("%d%d",&n,&c);
int *w=(int*)malloc(sizeof(int)*(n+1));//weights
int *v=(int*)malloc(sizeof(int)*(c+1));//values
int *x=(int*)malloc(sizeof(int)*(n+1));//goods chosed
int i;
for(i=1;i<=n;i++)
scanf("%d",&w[i]);//start with index 1
for(i=1;i<=n;i++)
scanf("%d",&v[i]);//start with index 1
w[0]=0;v[0]=0;
int **m=(int**)malloc(sizeof(int*)*(n+1));//m[i][j] means j capacity with i...n goods to choose
for(int i=0;i<n+1;i++){
m[i]=(int*)malloc(sizeof(int)*(c+1));
}
knapsack(n,c,w,v,m);
traceback(m,w,c,n,x);
printf("goods chosed:");
for(i=1;i<=n;i++)
if(x[i]==1)
printf("%d ",i);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
测试数据:
(1)有7个物品,w={2,3,5,7,1,4,1},v={10,5,15,7,6,18,3},背包容量c为15。
(2)有5个物品,w={2,2,6,5,4},v={6,3,5,4,6},背包容量c为10。