我想找到满足某些条件C(m)的最高值m = a * b,其中
1 <= a <= b <= 1,000,000.
为了做到这一点,我想按a * b的递减顺序迭代所有a,b对。
例如,对于最多5的值,顺序为:
5 x 5 = 25
4 x 5 = 20
4 x 4 = 16
3 x 5 = 15
3 x 4 = 12
2 x 5 = 10
3 x 3 = 9
2 x 4 = 8
2 x 3 = 6
1 x 5 = 5
1 x 4 = 4
2 x 2 = 4
1 x 3 = 3
1 x 2 = 2
1 x 1 = 1
到目前为止,我已经提出了类似BFS的树搜索,在那里我从当前&#34;访问过&#34;设置和挑选最高价值的候选人,但这是一个纠结的混乱,我不确定正确性。我想知道是否有某种我不知道的伎俩。
我也对任何单调函数f(a,b)排序的更一般情况感兴趣,如果存在这样的话。
为了说明,如果m 2 + m + 41是素数,则C(m)可以是&#34;否则返回true,否则返回false&#34;,但我真的在寻找一般方法。
答案 0 :(得分:3)
如果C(m)
是如此神奇,以至于您无法使用任何更好的技术直接找到解决方案,因此您确实需要按递减顺序遍历所有a*b
,这就是我要做的:< / p>
使用所有对(a, b)
初始化最大堆,使a = b
。这意味着堆包含(0, 0), (1, 1), ... , (1.000.000, 1.000.000)
。堆应该基于a * b
值。
现在不断:
(a, b)
。(a, b)
是否满足C(a * b)
。如果是这样,你就完成了。(a, b-1)
添加到堆中(提供b > 0
,否则不执行任何操作)。这是一个非常简单的O(n log n)
时间和O(n)
空间算法,前提是您可以快速找到答案(在几次迭代中)。这当然取决于C
。
如果遇到空间问题,当然可以通过在多个子问题中分解问题来轻松降低空间复杂度,例如2:
(500.000, 500.000), (500.001, 500.001), ... , (1.000.000, 1.000.000)
并找到最佳对(a, b)
。(0, 0), (1, 1), ... (499.999, 499.999)
执行相同操作。答案 1 :(得分:2)
这是使用Python中的堆执行此操作的一种不是特别有效的方法。这可能与你提到的BFS相同,但它相当干净。 (如果有人提出直接算法,那当然会更好。)
import heapq # <-this module's API is gross. why no PriorityQueue class?
def pairs_by_reverse_prod(n):
# put n things in heap, since of course i*j > i*(j-1); only do i <= j
# first entry is negative of product, since this is a min heap
to_do = [(-i * n, i, n) for i in xrange(1, n+1)]
heapq.heapify(to_do)
while to_do:
# first elt of heap has the highest product
_, i, j = to_do[0]
yield i, j
# remove it from the heap, replacing if we want to replace
if j > i:
heapq.heapreplace(to_do, (-i * (j-1), i, j-1))
else:
heapq.heappop(to_do)
答案 2 :(得分:1)
下面的代码将生成(并打印):
[(5, 5), (4, 5), (4, 4), (3, 5), (3, 4), (2, 5), (3, 3), (2, 4), (2, 3), (1, 5), (1, 4), (2, 2), (1, 3), (1, 2), (1, 1)]
这基本上就是你想要的,因为如果满足你的条件,代码可以提早破解。我认为这个问题的重点不是生成(a, b)
的所有可能组合。
算法的关键点是,在每次迭代中,我们需要考虑(a - 1, b)
和(a, b - 1)
。但是,如果a == b
为a <= b
,我们只需要考虑(a - 1, b)
。其余的是根据产品Q
维护元组队列中的顺序m
。
就效率而言,当插入Q
时,代码会从索引0
执行线性搜索。对于较大的a
和b
值,执行二分搜索而不是此线性搜索可能会或可能不会使事情变得更快。
为了进一步优化代码,我们可以将m
与(a, b)
一起存储在Q
中,这样我们就不必多次计算a * b
。同时使用带有m
的1D桶结构作为实现Q
的关键将会很有趣。
#!/usr/bin/python
def insert_into_Q((a, b), Q):
if (a == 0) or (b == 0):
return
pos = 0
for (x, y) in Q:
if (x == a) and (y == b):
return
if x * y < a * b:
break
pos = pos + 1
Q.insert(pos, (a, b))
def main(a, b):
Q = [(a, b)]
L = []
while True:
if len(Q) == 0:
break
(a, b) = Q.pop(0)
L.append((a, b)) # Replace this with C(a * b) and break if satisfied.
a1 = a - 1
b1 = b - 1
if (a == b):
insert_into_Q((a1, b), Q)
else:
insert_into_Q((a1, b), Q)
insert_into_Q((a, b1), Q)
print(L)
if __name__ == "__main__":
main(5, 5)
答案 3 :(得分:1)
注意:这是函数C(m)的测试,其中m <=某个目标。它不适用于OP的一般情况,但是是一个侧面案例。
首先找到满足C的最高数字,然后找到匹配该高数字的对。从1到1E12的二进制搜索,找到初始目标数几乎没有时间。找到匹配的对有点困难,但仍然没有分解那么糟糕。
代码:
public class TargetPractice {
private static final long MAX = 1000000L;
private long target;
public static void main(String[] args) {
Random r = new Random();
for (int i = 0; i < 5; i++) {
TargetPractice tp = new TargetPractice(r.nextInt((int) MAX), r.nextInt((int) MAX));
System.out.println("Trying to find " + tp.target);
System.gc();
long start = System.currentTimeMillis();
long foundTarget = tp.findTarget();
long end = System.currentTimeMillis();
System.out.println("Found " + foundTarget);
System.out.println("Elapsed time " + (end - start) + "\n");
}
}
public TargetPractice(long a, long b) {
target = a * b + 1;
}
private long binSearch() {
double delta = MAX * MAX / 2;
double target = delta;
while (delta != 0) {
if (hit((long) target)) {
target = target + delta / 2;
} else {
target = target - delta / 2;
}
delta = delta / 2;
}
long longTarget = (long) target;
for (int i = 10; i >= -10; i--) {
if (hit(longTarget + i)) {
return longTarget + i;
}
}
return -1;
}
private long findTarget() {
long target = binSearch();
long b = MAX;
while (target / b * b != target || target / b > MAX) {
b--;
if (b == 0 || target / b > MAX) {
b = MAX;
target--;
}
}
System.out.println("Found the pair " + (target/b) + ", " + b);
return target;
}
public boolean hit(long n) {
return n <= target;
}
}
打印:
试图找到210990777760
找到对255976,824260
找到210990777760
已过去的时间5
试图找到 414698196925
发现对428076,968749
发现 414698196924
经历时间27
试图找到75280777586
找到对78673,956882
发现 75280777586
已用时间1
试图找到75327435877
找到对82236,915991
发现 75327435876
经历时间19
试图找到187413015763
发现对243306,770277
找到187413015762
经历了时间23