让我首先澄清一下(在你们解雇我之前),这不是一个家庭作业问题而且我不是大学生。 :)
修改 感谢@Klas和其他人,我的问题现在归结为一个需要以编程方式解决的数学方程式。
我正在寻找解决Linear Diophantine Equation
的算法/代码。
对于像我这样的凡人来说,这就是这样一个等式的样子:
示例1:3x + 4y + 5z = 25
(找到x,y,z的所有可能值)
示例2:10p + 5q + 6r + 11s = 224
(找到p,q,r,s的所有可能值)
示例3:8p + 9q + 10r + 11s + 12t = 1012
(找到p,q,r,s,t的所有可能值)
我试着谷歌搜索无济于事。我本以为会编写一些代码来解决这个问题。如果你们遇到某种已经实现过这种情况的图书馆,请告诉我。如果解决方案是Java,没有什么可以更酷!算法/伪代码也可以。非常感谢。
答案 0 :(得分:3)
强力递归是一种选择,具体取决于您允许值的值或值的大小。
假设:用户输入(被乘数)总是不同的正整数。要找到的系数必须是非负整数。
算法:
Of the multiplicands, let M be the largest.
Calculate C=floor(F/M).
If F=M*C, output solution of the form (0,0,...,C) and decrement C
If M is the only multiplicand, terminate processing
Loop from C down to 0 (call that value i)
Let F' = F - i*M
Recursively invoke this algorithm:
The multiplicands will be the current set minus M
The goal value will be F'
For each solution output by the recursive call:
append i to the coefficient list and output the solution
答案 1 :(得分:2)
答案 2 :(得分:2)
我碰巧为此编写了Java代码。请自便。这些解决方案尚未经过广泛测试,但到目前为止似乎运行良好。
package expt.qp;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class LinearDiophantine {
private Map<Integer, Integer> sol = new LinkedHashMap<Integer, Integer>();
private Map<Integer, Integer> coeff = new HashMap<Integer, Integer>();
/**
* @param args
*/
public static void main(String[] args) {
// Fill up the data
// 3x + 4y + 5z + 3a = 25
LinearDiophantine ld = new LinearDiophantine();
ld.coeff.put(1, 1);ld.coeff.put(2, 2);ld.coeff.put(3, 3);ld.coeff.put(4, 4);
Map<Integer, Integer> coeffCopy = new HashMap<Integer, Integer>(ld.coeff);
int total=30;
// Real algo begins here
ld.findPossibleSolutions(total, coeffCopy);
}
private void findPossibleSolutions(int total, Map<Integer, Integer> coeff) {
int index=returnLargestIndex(coeff);
int range = (int) Math.floor(total/coeff.get(index));
if(range*coeff.get(index) == total) {
sol.put(index, range);
displaySolution();
//System.out.println();
range--;
}
if(coeff.size() == 1) {
return;
}
while(range>=0) {
int remTotal = total - range*coeff.get(index);
Map<Integer, Integer> coeffCopy = new HashMap<Integer, Integer>(coeff);
coeffCopy.remove(index);
sol.put(index, range);
findPossibleSolutions(remTotal, coeffCopy);
range--;
}
}
private void displaySolution() {
int total = 0;
for(int i : sol.keySet()) {
//System.out.print(coeff.get(i)+"("+sol.get(i)+"), ");
total = total + (coeff.get(i)*sol.get(i));
}
if(total != 30)
System.out.print(total+",");
}
/**
* @param coeff
*/
private int returnLargestIndex(Map<Integer, Integer> coeff) {
int largestKey = coeff.keySet().iterator().next();
for(int i : coeff.keySet()) {
if(coeff.get(i)>coeff.get(largestKey)) {
largestKey=i;
}
}
return largestKey;
}
}
答案 3 :(得分:1)
添加到Klas的非常准确的答案:
Hilbert的第10个问题询问是否存在用于确定任意丢番图方程是否有解的算法。对于一阶丢番图方程的解,确实存在这样的算法。然而,Yuri Matiyasevich在1970年证明了无法获得一般解决方案
答案 4 :(得分:1)
强力算法如下(3变量情况):
int sum = 25;
int a1 = 3;
int a2 = 4;
int a3 = 5;
for (int i = 0; i * a1 <= sum; i++) {
for (int j = 0; i * a1 + j * a2 <= sum; j++) {
for (int k = 0; i * a1 + j * a2 + k * a3 <= sum; k++) {
if (i * a1 + j * a2 + k * a3 == sum) {
System.out.println(i + "," + j + "," + k);
}
}
}
}
要对N变量大小写进行概括,您需要转换为递归形式。
对于某些函数O(f(size, a)^N)
,此算法为f
。
f
上设置界限,如下所示:size / MaxValue(a) <= f(size, a) <= size / MinValue(a)
。a[i]
都是1
)f(size, a)
是size
。无论哪种方式,这对N
的大值来说都是非常可怕的。因此,虽然递归N变量算法会更优雅,但它可能不太实用。
如果你愿意向Springer Verlag支付34欧元,这里的a link to a paper(根据摘要)包含一个解决N变量案例的算法。
答案 5 :(得分:1)
要么没有,要么无限多的解决方案。通常情况下,您有一个解决方案必须匹配的额外约束。你的问题就是这种情况吗?
让我们从最简单的情况开始,其中有两个unkowns a*x + b*y = c
:
第一步是使用Euclidean algorithm查找a
和b
的GCD,我们称之为d
。作为奖励,该算法提供x'
和y'
,使a*x' + b*y' = d
。如果d
没有划分c
,那么就没有解决方案。否则,解决方案是:
x = x' * (c/d)
y = y' * (c/d)
第二步是找到所有解决方案。这意味着我们必须找到所有p
和q
,以便a*p + b*q = 0
。如果(x,y)
和(X, Y)
都是解决方案,那么
a * (X-x) + b * (Y-y) = 0
对此的答案是p = b/d
和q = -a/d
其中d = GCD(a,b)
已经在步骤1中计算过。现在的一般解决方案是:
x = x' * (c/d) + n * (b/d)
y = y' * (c/d) - n * (a/d)
其中n是整数。
第一步很容易扩展到多个变量。我不确定第二步的概括。我的第一个猜测是找到所有系数对的解决方案并组合这些解决方案。
答案 6 :(得分:1)
这是Perl的解决方案。而是使用正则表达式进行攻击。
按照此博客post使用正则表达式求解代数方程式。
我们可以使用以下脚本3x + 2y + 5z = 40
#!/usr/bin/perl
$_ = 'o' x 40;
$a = 'o' x 3;
$b = 'o' x 2;
$c = 'o' x 5;
$_ =~ /^((?:$a)+)((?:$b)+)((?:$c)+)$/;
print "x = ", length($1)/length($a), "\n";
print "y = ", length($2)/length($b), "\n";
print "z = ", length($3)/length($c), "\n";
输出:x = 11,y = 1,z = 1
着名的Oldest plays the piano谜题最终成为一个3变量方程式
此方法适用于condition变量实际为正且常数为正。
答案 7 :(得分:0)
没有库这样做的原因类似于为什么你找不到一个库进行排列的原因 - 你生成了太多的数据,这可能是错误的。
更准确地说,如果您的n
个变量的总和为X
,那么您将获得O(Xn-1)
个答案。 X
和n
不一定非常大,因为这会成为一个问题。
也就是说,这里有一些Python可以非常高效地找出编码答案的所有必要信息:
def solve_linear_diophantine (*coeff_tuple):
coeff = list(coeff_tuple)
constant = coeff.pop()
cached = []
for i in range(len(coeff)):
# Add another cache.
cached.append({})
def solve_final (i, remaining_constant):
if remaining_constant in cached[i]:
return cached[i][remaining_constant]
answer = []
if i+1 == len(coeff):
if 0 == remaining_constant%coeff[i]:
answer = [(remaining_constant/coeff[i], [])]
else:
for j in range(remaining_constant/coeff[i] + 1):
finish = solve_final(i+1, remaining_constant - j*coeff[i])
if finish is not None:
answer.append((j, finish))
if 0 == len(answer):
cached[i][remaining_constant] = None
return None
else:
cached[i][remaining_constant] = answer
return answer
return solve_final(0, constant)
当我说“编码”时,数据结构如下所示。对于每个可能的系数,我们将获得一个(coefficient, [subanswers])
数组。只要有可能,它会重用subanswers以使数据结构尽可能小。如果你不能,你可以递归地将它扩展回一系列答案,这样你就会非常高效。 (实际上它是O(nX)
。)你很少重复逻辑来反复发现相同的事实。 (但是返回的列表可能会变得非常大,因为有大量的答案要返回。)