0-1背包问题: 若有物品n个,每个物品的价值Value,用vi表示,每个物品的重量weight用wi表示,其中vi和wi均为非负数。设背包的总容量为W,且W为非负数。现需要考虑的问题是:如何选择装入背包的物品,使装入背包的物品总价值最大。
(1)可以将背包的求解过程看作是一系列的决策过程,决定哪些物品应该放入背包,哪些物品不应该放入背包。如果一个问题的最优解包含n个物品,即x[i]=1,那么其余物品一定构成子问题1,2...n-1在容量W-wi时的最优解。如果不包含物品x[i]=0,那么其余物品一定构成子问题1,2...n-1在容量W-wi时的最优解。
(2)递归定义最优解的值 设c[i][w]表示背包的容量为w时i个物品导致的最优解的总价值,得到如下式子:
代码如下:
import java.util.Scanner;
public class KnapSack {
void DP(int n, int W, int c[][], int wi[], int vi[]) {
int i, w;
for (i = 1; i <= n; i++) {
System.out.print(i+"\t");
for (w = 0; w <= W; w++) {
if (wi[i] <= w) { //如果背包剩余的容量大于物品的重量
if (vi[i] + c[i - 1][w - wi[i]] > c[i - 1][w]){ //该物品放入重量为w的背包
c[i][w] = vi[i] + c[i - 1][w - wi[i]];
}
else {
c[i][w] = c[i - 1][w];//该物品不放入背包中
}
}
else c[i][w] = c[i-1][w];
System.out.print(c[i][w]+"\t");
}
System.out.println();
}
}
void outputDP(int n,int W,int w[] , int v[],int c[][]){
int [] x = new int[n];
int i;
for(i=n;i>1;i--){
if(c[i][W] == c[i-1][W]) {
x[i-1] = 0;
}
else{
x[i-1] =1;
W=W-w[i-1];
}
}
if(c[1][W]==0)
x[0] = 0;
else
x[0] = 1;
System.out.println("放入的物品的重量和价值为:");
for(i=0;i<n;i++){
if(x[i]==1)
System.out.printf("重量:%d 价值:%d\n",w[i+1],v[i+1]);
}
System.out.print("最优的物品放入分布为:");
for( i=0;i<n;i++){
System.out.print(x[i]+" ");
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner=new Scanner(System.in);
System.out.print("请输入背包的容量:");
int W=scanner.nextInt();
System.out.print("请输入物品的个数:");
int num=scanner.nextInt();
int [] w=new int[num+1];
int [] v=new int[num+1];
int [][] c=new int[num+1][W+1];
System.out.print("请输入物品的重量和价值:");
for(int i=1;i<=num;i++){
w[i]=scanner.nextInt();
v[i]=scanner.nextInt();
}
KnapSack a=new KnapSack();
System.out.println("当物品数i时,背包容量为w时,背包的价值为c[i][w],如下所示:");
for(int j=0;j<=W;j++)
System.out.print("\t"+j);
System.out.println();
a.DP(num, W, c, w, v);
a.outputDP(num, W, w, v, c);
System.out.println("背包最优解的总价值为:"+c[num][W]);
}
}
结果截图如下: