Java初解背包问题

时间:2023-02-12 18:42:08

Java初解背包问题

经典背包问题:

有n个重量和价值分别为w和v的物品,从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。

限制条件: 1<= n <=100

1<=w,v,<=100

1<= W <=1000

样例:

输入:

n=4 {w,v} = {{2,3},{1,2},{3,4},{2,2}} W = 5

输出:

7

解法一:

针对每个物品是否放入背包进行搜索试试

代码:

package thebackage;

/*
* 背包问题解法一
*/

public class FirstB {
int AW = 0;
int n;
int[] weight;
int[] value;
public FirstB(int n,int[] weight,int[] value) {
this.n = n;
this.weight = weight;
this.value = value;
}
public int FtheMax(int i,int j) {

if (n==i) {
//没有剩余物品
AW=0;
} else if(weight[i]>j){
//无法挑选这个物品
AW=FtheMax(i+1, j);
} else {
//在挑选和不挑选进行搜索
AW=max(FtheMax(i+1, j), FtheMax(i+1,j-weight[i])+value[i]);
}
return AW;
}

public int max(int a,int b) {
if (a>b) {
return a;
}else {
return b;
}

}
public static void main(String[] args) {
int n=4;
int w=5;
int[] value = {3,2,4,2};
int[] weight = {2,1,3,2};
FirstB firstB = new FirstB(n, weight, value);
System.out.println(firstB.FtheMax(0, w));

}

}
这种解法搜索深度为n,并且每一层都需要两次分支,最坏需要O(2^n)的时间
解法2可以尝试利用记忆化搜索进行优化

先上代码:

package thebackage;

/**
*
* @author linziyu
*优化背包问题
*/

public class SecondB {

int n;
int[] value;
int[] weight;
int values = 0;
int[][] dp = new int[100][100];//进行结果记录

public SecondB(int n,int[] value,int[] weight) {
this.n = n;
this.value = value;
this.weight = weight;

}

public int theBest(int i,int weights) {
if (dp[i][weights]>0) {
//已经计算过的话直接使用之前的结果
return dp[i][weights];
}

if(i==n){
values=0;
} else if (weight[i]>weights) {
values=theBest(i+1, weights);
} else {
values=max(theBest(i+1, weights), theBest(i+1,weights-weight[i])+value[i]);

}
//将结果记录在数组中
return dp[i][weights]=values;

}

public int max(int a,int b) {
if (a>b) {
return a;
} else {
return b;
}
}



public static void main(String[] args) {
int n=4;
int w=5;
int[] value = {3,2,4,2};
int[] weight = {2,1,3,2};
SecondB secondB = new SecondB(n, value, weight);
System.out.println(secondB.theBest(0,w));

}

}

此优化可以使得对于同样的参数,只会在第一次被调用到时执行递归部分,第二次之后都会直接返回,参数组合不过nW中, 所以只需O(nW)的复杂度就可以解决。