给出问题:
0/1-背包问题,每个项目都有权重w_i和值v_i。找出权重总和为W的项目的最大总价值。
但有两个限制:
我想找到一种注意两种约束的算法。我已经发现我一次可以注意其中一个。
这是我的实施,注重第1号(精确重量W):
public class KnapSackExactWeight {
public static void main(String[] args) {
int[] w = new int[] {4, 1, 5, 8, 3, 9, 2}; //weights
int[] v = new int[] {2, 12, 8, 9, 3, 4, 3}; //values
int n = w.length;
int W = 10; // W (max weight)
int[][] DP = new int[n+1][W+1];
for(int i = 1; i < n+1; i++) {
for(int j = 0; j < W+1; j++) {
if(i == 0 || j == 0) {
DP[i][j] = 0;
} else if (j - w[i-1] >= 0) {
DP[i][j] = Math.max(DP[i-1][j], DP[i-1][j - w[i-1]] + v[i-1]);
} else {
DP[i][j] = -Integer.MAX_VALUE;
}
}
}
System.out.println("Result: " + DP[n][W]);
}
}
Result: 22
这是我的实现,它考虑了constrait 2(甚至数量的项目):
public class KnapSackEvenAmount {
public static void main(String[] args) {
int[] weights = new int[] {4, 1, 5, 8, 3, 9, 2}; //weights
int[] values = new int[] {2, 12, 8, 9, 3, 4, 3}; //values
int n = weights.length;
int W = 10;
int[][] DP_odd = new int[n+1][W+1];
int[][] DP_even = new int[n+1][W+1];
for(int i = 0; i < n+1; i++) {
for(int j = 0; j < W+1; j++) {
DP_even[i][j] = -1;
DP_odd[i][j] = -1;
if(i == 0 || j == 0) {
DP_odd[i][j] = -1;
DP_even[i][j] = 0;
} else if(j - weights[i-1] >= 0) {
if(DP_odd[i-1][j - weights[i-1]] >= 0) {
DP_even[i][j] = Math.max(DP_even[i-1][j], DP_odd[i-1][j - weights[i-1]] + values[i-1]);
}
if(DP_even[i-1][j - weights[i-1]] >= 0) {
DP_odd[i][j] = Math.max(DP_odd[i-1][j], DP_even[i-1][j - weights[i-1]] + values[i-1]);
}
}
if(i > 0) {
DP_odd[i][j] = Math.max(DP_odd[i][j], DP_odd[i-1][j]);
DP_even[i][j] = Math.max(DP_even[i][j], DP_even[i-1][j]);
}
}
}
System.out.println("Result: " + DP_even[n][W]);
}
}
Result: 21
想法:我使用两个DP表(DP_even和DP_odd)并为DP_odd中具有奇数项目的背包以及DP_even中具有偶数项目的项目保存最佳解决方案。
现在我的问题是如何实现两个约束一起工作。有办法解决这个问题吗?
(如果我的问题不清楚,请问!)
答案 0 :(得分:3)
不确定这是否是解决此问题的最佳方法,但我在这里所做的是最初减少问题以适应约束。首先找到重量等于背包重量的可能偶数项目,然后找到具有最高值的组合
import java.util.Scanner;
import static java.lang.Math.pow;
public class subSet{
void subset(int num,int n, int x[])
{
int i;
for(i=1;i<=n;i++)
x[i]=0;
for(i=n;num!=0;i--)
{
x[i]=num%2;
num=num/2;
}
}
public static void main(String[] args) {
int n,d,sum,present=0;
int j;
System.out.println("enter the number of items");
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
int a[]=new int[n+1];
int x[]=new int[n+1];
System.out.println("enter the weights of items");
for(int i=1;i<=n;i++)
a[i]=sc.nextInt();
System.out.println("enter the values of items");
int v[]=new int[n+1];
for(int i=1;i<=n;i++)
v[i]=sc.nextInt();
System.out.println("enter the max weight");
d=sc.nextInt();
int sol=0;int max=0;
if(d>0)
{
for(int i=1;i<=Math.pow(2,n)-1;i++)
{
subSet s=new subSet();
s.subset(i,n,x);
sum=0;int count=0;
for(j=1;j<=n;j++)
if(x[j]==1)
{
sum=sum+a[j];
count++;
}
sol=0;
if(d==sum && count%2==0)
{
present=1;
for(j=1;j<=n;j++)
{
if(x[j]==1)
sol=v[j]+sol;
if(sol>max)
max=sol;
}
}
}
}
if(present==0)
System.out.println("Solution does not exists");
else
System.out.print("solution = "+max);
}
}
答案 1 :(得分:0)
我认为问题可能出在这一行:
DP_odd[i][j] = -1;
对于使用奇数次,您只能处以1的罚款。
如果您只是将其增加到更大的负数(例如整数的最大负值),我认为您当前的算法应该有效。