一个集合被传递给下面的这个方法,并且还传入一个条的长度。解决方案应输出集合中的数字,如果从集合中删除了集合中的某些数字,则会产生最少量的浪费长度。因此,条形长度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;
}
}
答案 0 :(得分:1)
你有几个问题。
一个是这一行:
int a = clonedSet.min(); //select next candidate
如果你走过你的例子,它会找到值1并首先使用它,所以1和4会被使用,但是6会不会。
您最好寻找最大值&lt; =剩余长度。
这条线对我来说也很奇怪:
WASTAGE +=a;
你应该减去我的想法,为什么要修改一个静态整数?
如果这是可以改变的东西,那么你应该把它传入,然后在你完成浪费的数量后再回传,那么你要返回一个新的类,解决方案和浪费的金额
对于递归,您需要拥有自己的示例,然后逐步浏览一个示例,看看它的行为是否符合您的预期。
你可能想看看这个循环:
for (int i = 0; i < possibleOrders.numberInSet(); i++) // the repeat
因为,如果你是递归地做这个,那么如果你有3种可能的解决方案,我相信你最终会做6次测试,而不是经历三次,这是你所期望的。
如果你删除for循环,你仍然可以。请输入打印声明,以便每次都能看到它。
<强>更新强>
根据更多信息,您要做的是收集所有可能的解决方案,然后您可以做的就是完成第一遍,获得以这种方式工作的解决方案。然后,向左或向右移动可能的解决方案,然后再试一次。
当你完全转移时,你会尝试各种组合,但不是每种可能的组合,但是,你可以采取这些解决方案,看看哪种是最佳的。
如果你想测试更多的组合,那么你需要循环删除一个项目,这可能是递归的。
所以,你需要在另一个函数中使用一个递归函数,所以你递归地遍历所有可能的组合,然后递归地寻找找到问题的解决方案。
我认为寻找max
可能是最好的,但这只是我的直觉,并且可以证明min
是最好的。
答案 1 :(得分:0)
我同意詹姆斯,你不需要/想要循环。据我所知,你的'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
}
}