确定线性不定方程的非负值解存在性的算法

时间:2009-09-23 18:46:28

标签: algorithm math number-theory

我正在寻找一种方法来确定是否存在方程式解决方案,例如: 3n1 + 4n2 + 5n3 = 456 ,其中 n1,n2,n3 为正整数。

或者更一般:是零或正整数 n1,n2,n3 ......解决方程 k1n1 + k2n2 + k3n3 ... = m 其中 k1,k2,k3 ...和 m 是已知的正整数。

我不需要找到解决方案 - 只是为了确定是否存在解决方案。

修改

关于该算法的实际应用:

在通信库中,我想在处理消息之前根据其大小决定给定消息是否有效。 例如:我知道消息包含零个或多个3字节元素,零个或多个4字节元素和零个或多个5个字节元素。我收到了456字节的消息,我想在进一步检查其内容之前确定其有效性。 当然,消息的标题包含每种类型的元素数量,但我想通过传递类似pair<MsgType,vector<3,4,5>>的内容在通信库级别进行首次检查。

7 个答案:

答案 0 :(得分:13)

你问的是正则表达式

(XXX | XXXX | XXXXX)*

匹配xx ... x,其中x出现456次。

这是O(n + a ^ 2)的解决方案,其中a是左侧最小的数字(在本例中为3)。

假设你的数字是6,7,15。我将以6x + 7y + 15z“可用”的形式拨打一个可以表达的号码。您要检查给定的号码是否可用。

如果你能得到一些数字n,那么肯定你能得到n + 6,n + 12,n + 18 - 一般来说,n + 6k所有k> = 0。另一方面,如果你不能得到一些数字n,那么n-6肯定也不可用(如果你能得到(n-6),那么(n-6)+ 6 = n将可用),这意味着n-12,n-18,n-6k也不可用。

假设您已确定15可用但9则不可用。在我们的例子中,15 = 6 * 0 + 7 * 0 + 15 * 1但无法以任何方式获得9。因此,根据我们之前的推理,15 + 6k可用于所有k> = 0和9-6k,对于所有k> = 0则不是。如果你有一些除以6的数字给3作为余数(3,9,15,21,...)你可以快速回答:数字&lt; = 9不可用,数字&gt; = 15。< / p>

足以确定所有可能的除法余数为6(即0,1,2,3,4,5)可用的最小数量是多少。 (我刚才已经证明剩余3的这个数字是15)。

怎么做:创建一个顶点为0,1,2,3,4,5的图形。对于你给出的所有数字k(7,15 - 我们忽略6),从x到(x + k)mod 6添加一条边。给它加权(x + k)div 6.使用Dijkstra's algorithm使用0作为初始节点。算法找到的距离正是我们要搜索的数字。

在我们的案例中(6,7,15),数字7产生0 - > 1(重量1),1 - > 2(重量1),2 - > 3(重量1),......,5 - > 0(权重1)和数字15给出0 - > 3(重量2),1 - > 4(重量2),......,5 - > 1(重量2)。从0到3的最短路径有一条边 - 它的权重是2.所以6 * 2 + 3 = 15是给出3作为余数的最小数。 6 * 1 + 3 = 9不可用(好吧,我们先前手工检查过。)

与正则表达式的连接是什么?好吧,每个正则表达式都有一个等价的有限自动机,我构造了其中一个。

允许多个查询的问题出现在Polish Olympiad上,我翻译了解决方案。现在,如果你现在听到一个人说计算机科学对真正的程序员没用,那就打他一下吧。

答案 1 :(得分:3)

根据this,如果{n1,n2,n3,...}的最大公因子不是m的除数,那么你没有解决方案。此页面仅显示{n1,n2}的示例,但它扩展到更大的系统。新问题是编写一种算法来寻找最大的公因子,但鉴于原始问题,这是微不足道的。

因此,你的算法的一部分会找到gcf({n1,n2,...})然后看它是否是m的因子。如果不是,则不存在解决方案。这并不能完全显示存在解决方案,但它可以快速向您显示不存在,这仍然有用。

答案 2 :(得分:2)

看起来你在谈论一个带有整数约束的不等式系统。现实是你正在为这个系统解决问题:

k1n1+k2n2+k3n3...=m
n1 >= 0
n2 >= 0
n3 >= 0

n1,n2,n3是整数的附加约束。这是一个linear programming问题。对您来说不幸的是,使用integer constraints is NP-complete解决此类系统的一般情况。但是,有很多算法可以为您解决。

答案 3 :(得分:2)

这与Frobenius coin problem有关,但是n> 3尚未解决。

答案 4 :(得分:1)

蛮力方法(伪代码):

def a = 3
def b = 4
def c = 5
def x = 456

for n1 = a to int(x / a) + 1 step a
  for n2 =b to int(x / b) + 1 step b
    for n3 = c to int(x / c) + 1 step c
      if a * n1 + b * n2 + c * n3 = x then
        print n1, n2, n3

另见http://mail.python.org/pipermail/python-list/2000-April/031714.html

编辑:在通讯库中这没有任何意义,因为它需要立即工作。在OP的应用程序中,我可能会使用某种哈希,但他的方法听起来很有趣。

答案 5 :(得分:1)

这是2号码的情况。我还没想出如何扩展它:

给定2个相对素数的整数x和y,存在正整数a和b,使得所有ax+by=c的{​​{1}}

基本上,这是有效的,因为如果你假设c>=(x-1)(y-1),你可以用(0,y,2y,3y,...,(x-1)y)表示所有整数mod x。现在,通过添加x的一些正数,你可以得到[(x-1)(y-1),(x-1)y]之间的所有整数,作为(x-1)之间的所有整数(y- 1)和(x-1)y-1先前已表达过。

  1. GCD(X,Y)。如果c不是倍数,则返回false。
  2. 如果GCD(x,y)> 1,用GCD划分x,y,c
  3. 如果c> (x-1)(y-1),返回true
  4. 其他蛮力
  5. 对于蛮力:

    x<y

答案 6 :(得分:1)

或许以下信息无关紧要,因为它无法处理一般情况,但......

如果问题是确定给定的正整数K是否可以形成为和3*n1 + 4*n2 + 5*n3,对于非负整数n1,n2,n3,则答案为“是”,对于K> = 3

罗森着名的教科书离散数学及其应用,p。第六版中的第287页,证明“使用感应,只需使用4美分和5美分的邮票即可形成12美分或更多的邮资。”

基础步骤是可以用3张4美分的邮票形成12美分的邮资。

归纳步骤考虑如果P(k)使用4美分的邮票是真的,那么只需用5美分的邮票代替4美分的邮票,以表明P(k + 1)为真。 如果P(k)是真的没有使用4美分的邮票,那么,因为k> = 12,我们需要至少3个5美分的邮票来形成我们的总和,3个5美分的邮票可以用4个4美分代替邮票达到k + 1.

要针对此问题扩展上述解决方案,只需要考虑几个案例。