Java 带扭结的背包01

Java 带扭结的背包01,java,knapsack-problem,Java,Knapsack Problem,我正在用Java做一个背包,我们只使用权重,不使用值。重量限制是1000磅。我们用键盘扫描了5个重量。 扭曲之处在于,你实际上可以超过1000,只要它的壁橱达到1000。因此,在一个场景中,我们有两个可能的权重990和1010,程序可以选择更高的权重。 扫描的数字不能高于1000 package kapsackidone; import java.util.Scanner; import java.io.BufferedReader; import java.io.InputStreamRead

我正在用Java做一个背包,我们只使用权重,不使用值。重量限制是1000磅。我们用键盘扫描了5个重量。 扭曲之处在于,你实际上可以超过1000,只要它的壁橱达到1000。因此,在一个场景中,我们有两个可能的权重990和1010,程序可以选择更高的权重。 扫描的数字不能高于1000

package kapsackidone;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.*;
public class Kapsack {

public static void main(String[] args) throws Exception {
    BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));

    int [] wt=new int[5];
    int W = 1000;

    System.out.println("Enter Weight 5 weights");
    for(int i=0; i<5; i++)
    {
        wt[i]=Integer.parseInt(reader.readLine());
    }   
    System.out.println(knapsack(wt, W));
}

public static int knapsack(int wt[], int W) {
    int N = wt.length;
    int[][] V = new int[N + 1][W + 1];

    for (int col = 0; col <= W; col++) {
        V[0][col] = 0;
    }


    for (int row = 0; row <= N; row++) {
        V[row][0] = 0;
    }

    for (int item=1;item<=N;item++){

    for (int weight=1;weight<=W;weight++){
        if(wt[item-1] > weight)
        {
            V[item][weight] = V[item-1][weight];
        }
        else if((weight - V[item-1][weight]) < (weight - (V[item-1][weight - wt[item-1]] + wt[item-1])))
        {
            V[item][weight] = V[item-1][weight];
        }
        else
        {
            V[item][weight] = V[item-1][weight - wt[item-1]] + wt[item-1];
        }
    }
    }

    return V[N][W];
    }
}
kapsackidone包装;
导入java.util.Scanner;
导入java.io.BufferedReader;
导入java.io.InputStreamReader;
导入java.io.*;
公共类卡萨克{
公共静态void main(字符串[]args)引发异常{
BufferedReader reader=新的BufferedReader(新的InputStreamReader(System.in));
int[]wt=新的int[5];
int W=1000;
System.out.println(“输入权重5权重”);

对于(inti=0;i我只运行两次

在第一次运行中,找到最佳重量小于1000的“经典”解决方案

在第二次运行中,将最大值1000增加到基于先前解决方案允许的最大可能值

不要担心“速度慢了两倍”,将复杂度乘以常数并不会改变复杂度,这是背包问题中的重要问题


如果您的代码正常工作,那么您可能可以这样计算最佳解决方案

System.out.println(knapsack(wt,2*W - knapsack(wt, W));
或者你可以这样写,以便更清楚地知道发生了什么(它的作用与上面的一行完全相同)


编辑:上面的解决方案适用于这种情况
选择尽可能大的解决方案,但它与1000的差异不得超过“低于1000”的最佳解决方案
。OP实际上希望有一点不同-“限制”保持不变,但它应该最接近1000,但尽可能高


因此,真正的解决方案是创建反向背包法,它将找到最小值的解决方案,但必须大于“min”变量

public static void main(String[] args) throws Exception {
    BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));

    int [] wt=new int[5];
    int W = 1000;

    System.out.println("Enter Weight 5 weights");
    for(int i=0; i<5; i++)
    {
        wt[i]=Integer.parseInt(reader.readLine());
    }   
    int bestClassicSolution = knapsack(wt, W);
    int differenceAgainstMaxWeight = W - bestClassicSolution;
    int newMaxWeight = W + differenceAgainstMaxWeight;
    int bestMaxSolution = reversedKnapsack(wt, newMaxWeight, W);
    int differenceAgainstWeightAboveW = W - bestMaxSolution;

    if (differenceAgainstWeightAboveW <= differenceAgainstMaxWeight){
        System.out.println(bestMaxSolution);
    } else {
        System.out.println(bestClassicSolution);
    }
}

public static int reversedKnapsack(int wt[], int W, int min) {
    //similar to knapsack method, but the solution must be as small as possible and must be bigger than min variable
}
publicstaticvoidmain(字符串[]args)引发异常{
BufferedReader reader=新的BufferedReader(新的InputStreamReader(System.in));
int[]wt=新的int[5];
int W=1000;
System.out.println(“输入权重5权重”);

对于(inti=0;i维基百科中的逐字记录-)

这个问题可以用动态规划在伪多项式时间内求解

x1,…,xN
我们希望确定是否存在一个和为零的非空子集。定义布尔值函数
Q(i,s)
为值(真或假),如果

“x1,…,席的非空子集,和S”相加。 因此,“给定一组整数,是否存在一个和为零的非空子集?”问题的解决方案是Q(N,0)的值

设A为负值之和,B为正值之和。显然,如果sB,Q(i,s)=false。因此这些值不需要存储或计算

创建一个数组来保存1的值Q(i,s)≤ 我≤ N和A≤ s≤ B

现在可以使用简单的递归来填充数组≤ s≤ B、 设置

Q(1,s):=(x1==s) 其中==是一个布尔函数,如果x1等于s,则返回true,否则返回false

然后,对于i=2,…,N,集

Q(i,s):=Q(i)− 1,s)或(xi==s)或Q(i)− 1,s− xi),用于≤ s≤ B

在计算Q的值之后,我们可以循环通过它们,取最接近极限的真值


至于S的值,我们需要取给我们的权重之和。

经典背包问题在a中讨论;经典问题的动态规划公式可以适用于以下问题

给定重量
w_1,…,w_n
和目标容量
w
,找到总重量最小但大于
w
的项目子集

为了避免病理病例,我们假设权重之和大于
W
,否则没有解决方案。让
W_MAX
表示所有权重之和

对于动态规划公式,让

m[i,j] for each i in 0,...,n and j in 0,...,W_MAX
表示通过丢弃
0,…,i
中的权重而获得的大于
W
的最小权重,总权重正好
j

我们获得

m[0,j] = W_MAX for each j in 0,...n
并得到递推关系

m[i,j] = min {
               m[i-1, i       ],       // corresponds to keeping weight i
               m[i-1, j - w[i]] - w[i] // corresponds to discarding weight i
             }
可以通过迭代
i=0,…,n
j=0,…,W_MAX
来实现评估;必须假设超出这些边界的
m
将产生
W_MAX
。与经典背包问题类似,实际要丢弃的项目集可以通过以下方法找到


最后,可以对给定实例进行两次优化;首先使用上述算法,然后使用经典背包算法。

我将首先将此问题评估为经典背包问题,取
value[I]=weight[I];

,其中
I
是第I项,最大重量为给定的最大重量(1000 kg)而item[]是一个数组,包含按重量升序排列的项。

让这个问题的答案是x,比如说990公斤,现在我将计算差值'd',
d=max\u wt-x;

迭代item[],直到item[i]超过d:
int i=0;
while(项目[i]
,最后将超过“d”的第一项添加到通过经典背包问题得到的答案中:
answer=dp[n-1][w-1]+item[i]\\dp[n-1][w-1]是经典答案

\\背包问题

问题是第二小重量(不可行解的最小可能值)可以任意大。考虑两个项目<代码> I1=1 < /代码>和<代码> I2= M < /代码>其中<代码> M < /代码>为非负整数;假设背包容量为代码>1 < /代码>。唯一可行的解决方案是<代码> I1 < /代码>,权重为<代码> 1 ,而最小的在。
m[i,j] = min {
               m[i-1, i       ],       // corresponds to keeping weight i
               m[i-1, j - w[i]] - w[i] // corresponds to discarding weight i
             }