订单(a,b)由a * b的结果对

时间:2014-08-07 04:58:11

标签: algorithm sorting

我想找到满足某些条件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;,但我真的在寻找一般方法。

4 个答案:

答案 0 :(得分:3)

如果C(m)是如此神奇,以至于您无法使用任何更好的技术直接找到解决方案,因此您确实需要按递减顺序遍历所有a*b,这就是我要做的:< / p>

使用所有对(a, b)初始化最大堆,使a = b。这意味着堆包含(0, 0), (1, 1), ... , (1.000.000, 1.000.000)。堆应该基于a * b值。

现在不断:

  1. 从堆中获取最大对(a, b)
  2. 验证(a, b)是否满足C(a * b)。如果是这样,你就完成了。
  3. 否则,将(a, b-1)添加到堆中(提供b > 0,否则不执行任何操作)。
  4. 这是一个非常简单的O(n log n)时间和O(n)空间算法,前提是您可以快速找到答案(在几次迭代中)。这当然取决于C


    如果遇到空间问题,当然可以通过在多个子问题中分解问题来轻松降低空间复杂度,例如2:

    1. 仅向堆中添加(500.000, 500.000), (500.001, 500.001), ... , (1.000.000, 1.000.000)并找到最佳对(a, b)
    2. (0, 0), (1, 1), ... (499.999, 499.999)执行相同操作。
    3. 充分利用这两种解决方案。

答案 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 == ba <= b,我们只需要考虑(a - 1, b)。其余的是根据产品Q维护元组队列中的顺序m

就效率而言,当插入Q时,代码会从索引0执行线性搜索。对于较大的ab值,执行二分搜索而不是此线性搜索可能会或可能不会使事情变得更快。

为了进一步优化代码,我们可以将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

相关问题