动态规划——01背包问题

如:背包的容量为W,现有n件物品,他们的重量分别为:w1,w2,w3……wn,价值分别为v1,v2,v3……vn,问如何存放物品,使背包内物品总价值达到最大,这就是01背包问题。

这里采用动态规划来解决。

这里用c(i,j)来表示当背包容量为j时,前i件物品的最大总价值

我们可以这样来想:每一件物品i都有两种可能,放与不放

1、放,可以先求出前i-1件物品在背包容量为j-wi时的最优解,再加上i物品的价值,就是当第i件物品放入背包中的最优解,

即:c(i,j)=c(i-1,j-wi)+vi;

2、不放,这个就简单了,直接c(i,j)=(i-1,j)。

最大值就取这两种情况里的最大值

当然当没有物品时或者背包容量为0时,即i=j=0时,c(i,j)=0

由此分析可得递推式:


例:有5件物品a,b,c,d,e,重量分别为3,5,6,4,2,价值分别为6,3,5,4,3,背包容量为10,下面这张表就是最大值形成过程

动态规划——01背包问题_第1张图片

最大值找到了,接下来就是找是那几件物品被放入背包中了,我们可以从j=10,i=5时倒着找,将c(i,j)与c(i-1,j)比较,若不同,则说明第i件物品被放入,即这里的13不同11,说明e物品被放入,接下来就只看e被放入的情况,最大值就与c(i-1,j-wi),即表中深红色那个10有关,此时i=4,j=8,将将c(i,j)与c(i-1,j)比较,10不同9,说明d被放入……可以发现a,d,e这三件物品被放入。

代码如下:

java实现

输出结果01表示物品不放入与放入

import java.util.Scanner;
public class DP {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		System.out.println("箱子容量:");
		int W=input.nextInt();//箱子容量
		System.out.println("物品数量:");
		int n=input.nextInt();//物品数量
		int []w=new int[n+1];//物品重量
		int []v=new int[n+1];//物品价值
		int [][]wv=new int[n+1][W+1];//最大价值
		int []a=new int[n+1];//存放 01,判断物品要不要放入	
		System.out.println("每一件物品的重量:");
		for(int i=1;i<=n;i++){
			w[i]=input.nextInt();
		}
		System.out.println("每一件物品的价值:");
		for(int i=1;i<=n;i++){
			v[i]=input.nextInt();
		}
		for(int i=1;i<=W;i++){
			for(int j=1;j<=n;j++){
					if(i>=w[j]){
					wv[j][i]=Math.max(wv[j-1][i-w[j]]+v[j], wv[j-1][i]);
					}
					else{
						wv[j][i]=wv[j-1][i];
					}
				}
		}
		int c=W;
		for(int i=n;i>0;i--){
			if(wv[i][c]==wv[i-1][c]){
				a[i]=0;
			}
			else{
				a[i]=1;
				c=c-w[i];
			}
		}
		System.out.println("取得最大价值:"+wv[n][W]);
		for(int i=1;i

动态规划——01背包问题_第2张图片

C实现

#include
#include
int max(int a,int b);
void backPack(int W,int w[],int v[],int n);
int main(){		
		printf("箱子容量:");
		int W;//箱子容量
		scanf("%d",&W);
		printf("物品数量:");
		int n;//物品数量
		scanf("%d",&n);
		int w[n];//物品重量
		int v[n];//物品价值
		printf("每一件物品的重量:");
		for(int i=0;i=0) {
				wv[i][j] = max(wv[i-1][j] , j-w[i]>=0 ? (wv[i-1][j-w[i]] + v[i]) : wv[i-1][j]);
			} else {
				wv[i][j] = j-w[i]>=0?v[i] : 0;
			}
		}
	}
		int c=W;
		for(int i=n-1;i>=0;i--){
			if(wv[i][c]==wv[i-1][c]){
				a[i]=0;
			}
			else{
				a[i]=1;
				c=c-w[i];
			}
		}
		printf("取得最大价值:%d\n",wv[n-1][W]);
		for(int i=0;i=b)
		return a;
	return b;
}

动态规划——01背包问题_第3张图片



你可能感兴趣的:(传统算法)