【问题标题】:Design Optimal Algorithm to find the values of 'a' and 'b'设计最优算法以找到“a”和“b”的值
【发布时间】:2015-11-28 11:41:13
【问题描述】:

假设给定一个合数 (n>3),可以写成:n = a*b,其中 a 和 b 是任意整数。

现在,我们的任务是计算 ab 的值,以使函数 f(a,b) = |a-b| 最小化。 .

我已经实现了 方法,如下所示:

int n;
cin >> n;      //  Take it from the user

/* Now, find the value of the a and b */
int a = 1;
int b = n;
int temp_a;
int temp_b;

for(temp_a=1; temp_a<=sqrt(n); temp_a++) {
    if(n % temp_a == 0) {
        temp_b = n / temp_a;

        if((temp_b - temp_a) < (b - a)) {
            b = temp_b;
            a = temp_a;
        }
    }
}

print a and b

但希望将其减少到 或更好,如果可能

【问题讨论】:

    标签: algorithm optimization numbers


    【解决方案1】:

    您想找到 N 的最大除数不大于 sqrt(N)。最简单的方法是遍历所有可能的除数并检查它们。在最坏的情况下需要 O(sqrt(N)) 时间。

    不幸的是,在最坏的情况下,没有办法在 O(log N) 时间内解决这个问题。事实上,对于任何 p,即使在 O((log N)^p) 时间内也不可能做到这一点。很容易证明,如果可能,那么您将能够在其大小(以字节为单位)的多项式时间内找到任意数字的prime factorization。现在没有人可以做到,并且有一个广泛使用的RSA cryptosystem,它强烈依赖于没有人可以如此快速地分解数字这一事实。这也是大家都害怕quantum computers的原因之一=)

    但是,有些算法渐进地比 O(sqrt(N)) 更快。此外,还有一些用于分解的更快的启发式算法。我强烈建议您阅读wikipedia article 关于此事。

    稍微提高复杂度的一种方法是预先计算所有素数,直到 sqrt(N)。然后,如果您尝试仅将 N 除以它们,您将能够找到 N 的素因数分解。了解素数分解后,您可以通过递归搜索有效地迭代所有可能的除数。找到分解所花费的时间与检查素数的时间一样多,即 O(sqrt(N) / log(N))。迭代所有除数所花费的时间与这些除数的数量成正比,即asymptotically less than any polynomial of N

    【讨论】:

      【解决方案2】:

      我花了很多时间来寻找这个问题的最佳解决方案,但失败了。然后我尝试测试@psyco 的方法是更好还是@Nyavro 的方法更好。就我个人而言,我认为从sqrt(n) to 1 开始倒计时一定更好,但是为了检查@psyco 的论点,我在python 程序中实现了这两种方法,并绘制了一个图表来比较两者可以用来找到解决方案的迭代次数。该图适用于 4 到 10000 之间的所有合数。下面是我的 Python 实现:

      import matplotlib.pyplot as plt
      import math
      X = 10001
      n1 = [0]*X
      n2 = []
      for i in range(2, int(math.sqrt(X))+1):
          if n1[i] == 0:
              for j in range(i*i, X, i):
                  n1[j] = 1
      
      for i in range(4, X):
          if n1[i] == 1:
              n2.append(i)
      
      #print n2
      count = []
      count2 = []
      for n in n2:
          a = 1
          b = n
          c = 0
          flag = 0
          for ta in range(int(math.sqrt(n)), 0, -1):
              c += 1
              if n % ta == 0:
                  tb = n / ta
                  flag = 1
                  if tb-ta <= b-a:
                      a = ta
                      b = tb
                      if flag == 1:
                          break
          count.append(c)
          a = 1
          b = n
          c = 0
          for ta in range(1, int(math.sqrt(n))+1):
              c += 1
              if n % ta == 0:
                  tb = n / ta
                  if tb-ta <= b-a:
                      a = ta
                      b = tb
      
          count2.append(c)
      
      plt.plot(n2, count, 'o')
      plt.plot(n2, count2, 'o')
      plt.show()
      

      这是输出图:

      上面的绿色边框是@psyco 的代码,蓝色边框是@Nyavro 的方法。尽管在许多情况下@Nyavro 的方法更好。

      【讨论】:

      • 你是对的。我知道,它可以以相反的顺序完成。但是,关键案例尚未涵盖。他们仍然需要同样的时间。这就是为什么我问是否有可能设计一种算法来降低复杂度而不是优化它
      【解决方案3】:

      考虑不是从 1 迭代到 sqrt(n),而是从 sqrt(n) 向下迭代到 1。首先找到的除数给出了答案,您不需要进一步进行

      【讨论】:

      • 是的,这会很棒。但是,这不是最理想的。我可以给你一个测试用例,你和我的方法将需要相同的时间来执行
      • 同意。但不幸的是,我无法想象找到除数的更好方法
      • 3125 视为测试用例,您的方法大约需要 30 步,而我的方法大约需要 25 步。
      猜你喜欢
      • 1970-01-01
      • 2020-08-16
      • 2018-01-22
      • 2019-05-16
      • 2015-11-14
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      相关资源
      最近更新 更多