我正在尝试实现回溯算法,以平衡秤上的权重。它是用于大学的,因此有一些我必须使用的权重(0、2、7、20、70、200、700)。权重可以多次放置在秤上以匹配输入。例如:input(80)-> result(20,20,20,20)或input(16)-> result(7,7,2)。 我必须使用回溯和递归。
如果提案有误,我很难理解如何进行回溯。我只能退后一步,但是如果正确的解决方案需要退后两步,我的算法就会失败。
所以我的方法isInvalid()正在检查所有配重的总和是否高于输入值。如果是这样,它将除去最后的重量。 我想这是我的问题。对于输入(16),它会产生(7,7,2)->正确。 但是对于input(21)来说,它永远不会结束,因为它试图加20,然后再试图加7。然后它将超过21并删除7,但永远不会删除20。
/ *这是我的回溯算法* /
public Proposal calc(Proposal proposal) {
Proposal result;
if(proposal.isInvalid()) return null;
if(proposal.isSolution()) return proposal;
for (int i : proposal.possibleNextSteps()) {
Proposal newProposal = new Proposal(proposal.getWeight(), proposal.getCounterWeights());
newProposal.apply(i);
result = calc(newProposal);
if (result != null) return result;
}
return null;
}
/ *这是提案类别(仅必填部分)* /
public class Proposal {
private int weight;
private ArrayList<Integer> counterWeights;
private static Integer[] weights = {0, 2, 7, 20, 70, 200};
public Proposal(int weight, ArrayList<Integer> counterWeights) {
this.weight = weight;
this.counterWeights = counterWeights;
Arrays.sort(weights, Collections.reverseOrder());
}
public boolean isInvalid() {
if(counterWeights.stream().mapToInt(i -> i.intValue()).sum() > weight) {
counterWeights.remove(counterWeights.size()-1);
return true;
}
return false;
}
public boolean isSolution() {
return counterWeights.stream().mapToInt(value -> value).sum() == weight;
}
public Integer[] possibleNextSteps() {
return weights;
}
public void apply(int option) {
this.counterWeights.add(option);
}
}
我在做什么错? 而且,这是反转我的权重数组的正确方法吗?
谢谢!
编辑: 我尝试了不同的东西。 我改变了这个:
Proposal newProposal = new Proposal(proposal.getWeight()- proposal.getSum(), new ArrayList<>());
这:
public boolean isInvalid() {
return counterWeights.stream().mapToInt(value -> value).sum() > weight;
}
因此,现在如果我在调试模式下逐步进行操作,它几乎可以完成我想做的事情,但是它不会将解决方案从递归传递到以前的解决方案,因此它们不会累加最终解决方案。 因此,基本上,我将问题分解为较小的问题(一旦找到合适的权重,我将使用总权重和已经找到的解决方案之间的差值递归调用该方法)。但是,如何将解决方案传递给调用方法?
答案 0 :(得分:0)
在以下实现中,解决方案是系数数组。索引i处的系数是位置i处的权重出现在溶液中的次数。
请注意,您可以有几种解决方案给出相同的总权重,此实现将它们全部解决。将其更改为仅返回找到的第一个解决方案很容易。
递归方法void solve(int weight, int n, int total)
尝试为其总权重不大于目标权重的所有整数创建索引n
。
public class Solver {
private final int[] weights;
private int[] current;
private final List<int[]> solutions = new ArrayList<>();
public Solver(int...weights) {
this.weights = weights;
}
public int[][] solve(int weight) {
current = new int[weights.length];
solutions.clear();
solve(weight, 0, 0);
return solutions.toArray(new int[solutions.size()][]);
}
public void printSolution(int[] solution) {
int total = 0;
for (int i = 0; i < solution.length; ++i) {
for (int j = 0; j < solution[i]; ++j) {
System.out.print(weights[i] + " ");
total += weights[i];
}
}
System.out.println(" total: " + total);
System.out.println();
}
private void solve(int weight, int n, int total) {
if (n >= current.length) {
if (total == weight) {
solutions.add(current.clone());
}
} else {
solve(weight, n+1, total);
while (total < weight) {
++current[n];
total += weights[n];
solve(weight, n+1, total);
}
current[n] = 0;
}
}
}