使用 Java,一些通用的简单实现至少需要两个类:
一些委托传递给递归算法,因此无论执行在哪里,您都可以接收更新。类似的东西:
public interface IDelegate {
public void found(List<CombinationFinder.FoundElement> nstack);
}
for 实现,类似于:
public class CombinationFinder {
private CombinationFinder next;
private int multiplier;
public CombinationFinder(int multiplier) {
this(multiplier, null);
}
public CombinationFinder(int multiplier, CombinationFinder next) {
this.multiplier = multiplier;
this.next = next;
}
public void setNext(CombinationFinder next) {
this.next = next;
}
public CombinationFinder getNext() {
return next;
}
public void search(int max, IDelegate d) {
Stack<FoundElement> stack = new Stack<FoundElement>();
this.search(0, max, stack, d);
}
private void search(int start, int max, Stack<FoundElement> s, IDelegate d) {
for (int i=0, val; (val = start + (i*multiplier)) <= max; i++) {
s.push(i);
if (null != next) {
next.search(val, max, s, d);
} else if (val == max) {
d.found(s);
}
s.pop();
}
}
static public class FoundElement {
private int value;
private int multiplier;
public FoundElement(int value, int multiplier) {
this.value = value;
this.multiplier = multiplier;
}
public int getValue() {
return value;
}
public int getMultiplier() {
return multiplier;
}
public String toString() {
return value+"*"+multiplier;
}
}
}
最后,设置和运行(测试):
CombinationFinder a1 = new CombinationFinder(20);
CombinationFinder a2 = new CombinationFinder(5);
CombinationFinder a3 = new CombinationFinder(10);
a1.setNext(a2);
a2.setNext(a3);
a1.search(100, new IDelegate() {
int count = 1;
@Override
public void found(List<CombinationFinder.FoundElement> nstack) {
System.out.print("#" + (count++) + " Found : ");
for (int i=0; i<nstack.size(); i++) {
if (i>0) System.out.print(" + ");
System.out.print(nstack.get(i));
}
System.out.println();
}
}
});
将输出 36 个解决方案。
有了这个概念,您可以拥有任意数量的内部循环,甚至可以通过继承自定义每个内部循环。您甚至可以毫无问题地重用对象(即:a1.setNext(a1);)。
** 更新 **
仅仅因为我喜欢monty的solution,我忍不住测试了它,结果如下,稍作调整。
免责声明算法的所有功劳归monty
public class PolynomialSolver {
private SolverResult delegate;
private int min = 0;
private int max = Integer.MAX_VALUE;
public PolynomialSolver(SolverResult delegate) {
this.delegate = delegate;
}
public SolverResult getDelegate() {
return delegate;
}
public int getMax() {
return max;
}
public int getMin() {
return min;
}
public void setRange(int min, int max) {
this.min = min;
this.max = max;
}
public void solve(int[] constants, int total) {
solveImpl(constants, new int[constants.length], total, 0, 0);
}
private void solveImpl(int[] c, int[] v, int t, int n, int r) {
if (n == c.length) { //your end condition for the recursion
if (r == t) {
delegate.solution(c, v, t);
}
} else if (r <= t){ //keep going
for (int i=min, j; (i<=max) && ((j=r+c[n]*i)<=t); i++) {
v[n] = i;
solveImpl(c, v, t, n+1, j);
}
}
}
static public interface SolverResult {
public void solution(int[] constants, int[] variables, int total);
}
static public void main(String...args) {
PolynomialSolver solver = new PolynomialSolver(new SolverResult() {
int count = 1;
@Override
public void solution(int[] constants, int[] variables, int total) {
System.out.print("#"+(count++)+" Found : ");
for (int i=0, len=constants.length; i<len; i++) {
if (i>0) System.out.print(" + ");
System.out.print(constants[i]+"*"+variables[i]);
}
System.out.println(" = " + total);
}
});
// test some constants = total
solver.setRange(-10, 20);
solver.solve(new int[] {20, 5, 10}, 100); // will output 162 solutions
}
}