问题描述
借助离散数学的应用,python中解决此问题的最快算法是什么:
使用等式 ax + by = d ,其中 a,b 和 d 是用户输入,在| L范围内搜索 x和y 的整数对, R | (包括 L和R )满足方程式。
L和R 也是用户输入。
按升序输出 x和y 的所有可能值。如果没有可能的配对,则打印 无 。
情况1:
a = 1
b = 5
d = 40
L = 0
R = 10
Result:
0 8
5 7
10 6
情况2:
a = 14
b = 91
d = 53
L = 1
R = 100
Result:
none
这是我的代码,但我认为搜索的方法快得多。这太低效了。
a = int(input())
b = int(input())
d = int(input())
L = int(input())
R = int(input())
isNone = True
for x in range(L,R+1):
for y in range(L,R+1):
if (a*x) + (b*y) == d:
print(x,y)
isNone = False
if isNone: print("none")
是否可以使用 O(1) 算法?最快的方法是什么?
解决方法
我想您要应用的身份如下(直接来自维基百科,尽管在大多数离散的数学课本中也可以找到类似的措词,或者可以自己证明):
最简单的线性Diophantine方程采用ax + by = c的形式,其中a,b和c为整数。解决方案由以下定理描述:
仅当c是a和b的最大公约数的倍数时,该Diophantine方程才具有解(其中x和y是整数)。此外,如果(x,y)是一个解,则其他解的形式为(x + kv,y-ku),其中k是任意整数,u和v分别是a和b的商通过a和b的最大公约数。
这几乎立即回答了这个问题,特别是因为它的标准证明使用了称为“欧几里得算法”的东西。为了简单起见,我们将执行以下操作:
- 在向前方向上使用欧几里得算法来找到
g = gcd(a,b)
。 - 通过欧几里得算法反求解以找到
_x,_y
这样的_x*a + _y*b == g
。 - 如果
d
不是g
的倍数,则不可能有任何解决方案,因此请尽早退出。 - 否则,
x,y = _x*(d//g),_y*(d//g)
是可能的解决方案。使用它来查找所需范围内的所有解决方案。
def gcd(a,b):
# forward euclidean algorithm
q,r,x,qs = None,b,a,[]
while x%r:
(q,r),x = divmod(x,r
qs.append(q)
# save the gcd for later
g = r
# backsolve euclidean algorithm
if not qs:
return 1,1-a//b,g
theta,omega = 1,-qs[-1]
for q in reversed(qs[:-1]):
theta,omega = omega,theta - q * omega
# theta * a + omega * b == g
# g might be negative,but we don't care about a canonical solution
return theta,omega,g
def idivide_zero(a,b):
# integer division a/b,round toward 0 instead of round down
q = a // b
if q < 0 and b*q != a:
q += 1
return q
def bounded_solutions(a,d,L,R):
_x,_y,g = gcd(a,b)
if d%g:
return
# a*x + b*y == d
x,_y*(d//g)
# solutions are of the form (x+k*v,y-k*u)
u,v = a//g,b//g
# The next trick is to find all solutions in [L,R].
# Basically,we need L <= x+k*v <= R and L <= y-k*u <= R.
# Note that valid choices of k exist in a contiguous interval,so
# we only have to find the lower and upper bounds to be able to
# quickly enumerate all options.
xb = sorted(idivide_zero(b-x,v) for b in (L,R))
yb = sorted(idivide_zero(y-b,u) for b in (L,R))
m,M = min(xb[0],yb[0]),max(xb[1],yb[1])
for k in range(m,M+1):
yield x+k*v,y-k*u
a = int(input())
b = int(input())
d = int(input())
L = int(input())
R = int(input())
empty = True
for x,y in bounded_solutions(a,R):
print(x,y)
empty = False
if empty:
print('none')
代码未经测试。本质上是正确的,但是可能还需要进行一些调试。