【问题标题】:Finding the numbers from a set which give the minimum amount of waste从一组中找出产生最少浪费的数字
【发布时间】:2011-04-15 18:04:51
【问题描述】:

一个集合被传递给下面的这个方法,并且一个条的长度也被传递进来。如果从条中删除集合中的某些数字,则解决方案应该输出集合中的数字,这些数字会产生最少的浪费长度。所以,条长 10,集合包括 6,1,4,所以解决方案是 6 和 4,浪费是 0。我在通过集合回溯的条件方面遇到了一些问题。我还尝试使用浪费的“全局”变量来帮助回溯方面,但无济于事。

SetInt 是一个手工制作的集合实现,它可以添加、删除、检查集合是否为空并返回集合中的最小值。

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package recback;


public class RecBack {

   public static int WASTAGE = 10;

    public static void main(String[] args) {



         int[] nums = {6,1,4};
        //Order Numbers

        int barLength = 10;
        //Bar length

        SetInt possibleOrders = new SetInt(nums.length);
        SetInt solution = new SetInt(nums.length);
        //Set Declarration


        for (int i = 0; i < nums.length; i++)possibleOrders.add(nums[i]);
        //Populate Set

        SetInt result = tryCutting(possibleOrders, solution, barLength);
        result.printNumbers();


    }

    private static SetInt tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft)
      {



        SetInt clonedSet = possibleOrders.cloneSet(); //initialise selection of candidates

        for (int i = 0; i < possibleOrders.numberInSet(); i++) // the repeat
          {

            int a = clonedSet.min(); //select next candidate

            if (a <= lengthleft) //if accecptable
              { 
                solution.add(a); //record candidate
                lengthleft -= a;
                clonedSet.remove(a); //remove from original set

                if (!clonedSet.isEmpty()) //solution not complete
                  {
                    WASTAGE +=a;
                    tryCutting(clonedSet, solution, lengthleft);//try recursive call

                    if (lengthleft > WASTAGE)//if not successfull
                      {
                        WASTAGE += a;
                        solution.remove(a);
                      }

                  } //solution not complete
              }
          } //for loop
        return solution;

      }
  }

【问题讨论】:

    标签: java recursion backtracking


    【解决方案1】:

    你有几个问题。

    一个是这一行: int a = clonedSet.min(); //select next candidate

    如果您浏览您的示例,它会找到值 1 并首先使用它,因此会使用 1 和 4,但不会使用 6。

    您最好寻找

    这句话对我来说也很奇怪:

    WASTAGE +=a;

    我认为你应该减去,为什么要修改静态整数?

    如果这是可变的,那么你应该把它传入,然后在你完成后传回浪费的数量,所以有一个你返回的新类,解决方案和浪费的数量.

    对于递归,您将希望有自己的示例,然后一次遍历一个,看看它的行为是否符合您的预期。

    你可能想看看这个循环:

    for (int i = 0; i &lt; possibleOrders.numberInSet(); i++) // the repeat

    因为,如果您以递归方式执行此操作,那么如果您有 3 种可能的解决方案,我相信您最终将进行 6 次测试,而不是像您期望的那样经历 3 次。

    如果您删除 for 循环,您应该仍然可以。放入打印语句,以便您每次都可以看到它。

    更新:

    根据更多信息,您要做的是收集所有可能的解决方案,然后您可以做的是通过并完成第一遍,获得以这种方式工作的解决方案。然后,向左或向右移动可能的解决方案,然后再试一次。

    当你一直在移动时,你会尝试各种组合,但不是所有可能的组合,但是,你可以采用这些解决方案,看看哪个是最佳的。

    如果您想测试更多组合,则需要循环删除一个项目,这可能是递归的。

    因此,您将需要一个递归函数包含在另一个函数中,因此您递归地遍历所有可能的组合,然后递归地寻找问题的解决方案。

    我认为寻找max 可能是最好的,但这只是我的直觉,可以证明min 是最好的。

    【讨论】:

    • 这里的问题是它必须回溯,所以如果值没有达到最佳结果,那么刚刚添加到解决方案中的结果会被再次删除。以便回溯和测试。我们被告知它可以用最小的结果来完成。它也不应该是静态的,那是我的错。最后,循环应该测试每个可能的解决方案,所以如果集合是 2、6、2、4;可以找到的解决方案是:6,4 & 6,2,2 我希望这是有道理的!
    【解决方案2】:

    我同意 James 的观点,你不需要/想要循环。据我了解,您的“tryCutting”算法会列出可能的订单、正在考虑的当前解决方案以及如果您要剪切当前解决方案所剩下的长度。然后你需要:

    • 从 订单。如果它比剩下的长度长,请不要再尝试。否则,
    • 第一种情况:你不履行 那个切割 - 尝试用新的再次切割 订单列表和当前的相同 长度
    • 第二种情况:你确实履行了 那个切口。将其添加到当前 解决方案和 tryCutting 与新的订单列表和长度 减少了那个削减。最后拿 它再次脱离当前的解决方案(对于 回溯)
    • 放最短切 返回订单(用于回溯)

    现在,对于您尝试的每种情况,检查剩余的长度与您目前为止的全球最佳情况。它比使用当前解决方案(的克隆)更新全局更短。

    这将为您提供单一的最佳解决方案,或者如果有几个同样好的解决方案,则其中之一。要获得所有解决方案,您需要一个 SetInts 的全局列表。如果您找到比当前更好的解决方案,请清除列表并添加新解决方案。如果它等于当前最好的,只需添加它。

    代码如下:

    public static void main(String[] args) {
        int[] nums = {6,1,4};          //Order Numbers
        int barLength = 10;         //Bar length
        bestSolution = new HashSet<SetInt>();
        bestWastage = barLength;
        SetInt possibleOrders = new SetInt(nums.length);
        SetInt solution = new SetInt(nums.length);         //Set Declarration
        for (int i = 0; i < nums.length; i++) {
            possibleOrders.add(nums[i]);         //Populate Set
        }
        tryCutting(possibleOrders, solution, barLength);
        for (SetInt result : bestSolution) {
            result.printNumbers();
        }
    
    }
    
    private static int bestWastage;
    private static Set<SetInt> bestSolution;
    
    private static void tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft) {
        if (lengthleft < bestWastage) {
            // Better than the best solution
            bestWastage = lengthleft;
            bestSolution.clear();
            bestSolution.add(solution.cloneSet());
        } else if (lengthleft == bestWastage) {
            // Just as good as the best solution
            bestSolution.add(solution.cloneSet());
        }
        int a = possibleOrders.min(); //select next candidate
        if (a <= lengthleft) { // If acceptable
            possibleOrders.remove(a); // Remove it
            tryCutting(possibleOrders, solution, lengthleft); // Try without that cut
            solution.add(a); // add to the solution
            tryCutting(possibleOrders, solution, lengthleft - a); // Try with that cut
            solution.remove(a); // remove again
            possibleOrders.add(a); // add the candidate back on again
        }
    }
    

    【讨论】:

    • 如果您这样做,我将不胜感激。
    • 我自己用和你类似的方法解决了这个问题。我添加了第二个递归调用,但我没有实现哈希集。但是我认为,如果我这样做,它将帮助我存储多个解决方案。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多