特定除数的最优算法

时间:2012-04-13 18:43:20

标签: php algorithm

不重复 - optimal algorithm for finding unique divisors

我遇到了这个问题。我无法找到最佳算法。

问题是:

给定自然数的列表L(数字可能非常大)和数字N,确定N的除数的最佳算法是什么不分割列表L中的任何数字。列表中的数字可以是重复的,即一个数字可以出现不止一次。

观察:

d的某些除数N的除数也是N的除数。

我的方法是:

  1. 找到N
  2. 的除数
  3. 按相反顺序排序L(最大元素为第1个元素)。
  4. d的foreach divisor N,我检查它是否划分列表中的任何元素。(当你来检查列表中小于d的元素时停止,因为列表已排序)
  5. 如果d除以列表L中的某个数字,那么我不会检查d的任何除数,也就是说,我跳过此检查。
  6. 最终,左边的除数既不会被列入列表中的任何数字,也不会被跳过。这个计数是最终答案。
  7. 但是这个算法并不是这个问题的最佳选择。

    有关更好算法的想法吗?

3 个答案:

答案 0 :(得分:0)

您需要了解的是: co-primes (或相对素数

  

在数论中,数学的一个分支,两个整数a和b   据说是互质(也拼写共同素数)或相对素数   只有正整数才能将它们均分为1。

所以要“转码”你的问题:

您基本上想要从N列表中找到L的副本数量。

ab是共同素数时?

enter image description here

  

如果两个数字相对素数则为最大公约数(GCD)   是1

PHP中的示例代码(对于GCD):

<?php
$gcd = gmp_gcd("12", "21");
echo gmp_strval($gcd) . "\n";
?>

简单地说:

  • $count = 0
  • 列表e中的Foreach元素L:计算GCD(e,N)
  • 他们的GCD是1吗?如果是,则它们是互质的(因此Ne没有公约除数)。算了一下。 $count++

这就是它的全部内容。

答案 1 :(得分:0)

首先,分解n并以下列方式表示:p1:k1,p2:k2,...,pm:km,使得p1,p2,...都是素数,n = p1 ^ k1 * p2 ^ k2 ....

现在,迭代r1,r2,r3,...,rm使得r1&lt; = k1,r2&lt; = k2,...,rm&lt; = km并检查p1 ^ r1 * p2 ^ r2 .. 。* pm ^ rm除以L中的任何数字。如果不将计数增加1。

优化:为r1选择一个值。看看p1 ^ r1是否除以L中的任何数字。如果是,则为r2选择一个数字,依此类推。如果p1 ^ r1没有除以L中的任何数字,则将计数增加(k2 + 1)(k3 + 1) .. *(km + 1)。

示例N = 72,L = [4,5,9,12,15,20]: 将N写为原始乘积:2:3,3:2(2 ^ 3 * 3 * 2 = 72)。

p1=2, p2=3, k1=3, k2=2
count=0
r1=0:
    r2=0:
        Divides 4
r1=0:
    r2=1:
        Divides 9
r1=0:
    r2=2:
        Divides 9
r1=1:
    r2=0:
        Divides 4
r1=1:
    r2=1:
        Divides 12
r1=1:
    r2=2:
        L not divisible by 18. Count+=1 = 1
r1=2:
    r2=0:
        Divides 4
r1=2:
    r2=1:
        Divides 12
r1=2:
    r2=2:
        L not divisible by 36. Count+=1 = 2
r1=3:
    r2=0:
        L not divisible by 8. Count+=(k2+1) +=(2+1) = 5

答案 2 :(得分:0)

<?php

class Divisors {
  public $factor = array();

  public function __construct($num) {
    $this->num = $num;
  }

  // count number of divisors of a number
  public function countDivisors() {
    if ($this->num == 1) return 1;

    $this->_primefactors();

    $array_primes = array_count_values($this->factor);
    $divisors = 1;
    foreach($array_primes as $power) {
      $divisors *= ++$power;
    }
    return $divisors;
  }

  // prime factors decomposer
  private function _primefactors() {
    $this->factor = array();
    $run = true;
    while($run && @$this->factor[0] != $this->num) {
      $run = $this->_getFactors();
    }
  }

  // get all factors of the number
  private function _getFactors() {
    if($this->num == 1) {
      return ;
    }
    $root = ceil(sqrt($this->num)) + 1;
    $i = 2;
    while($i <= $root) {
      if($this->num % $i == 0) {
        $this->factor[] = $i;
        $this->num = $this->num / $i;
        return true;
      }
      $i++;
    }
    $this->factor[] = $this->num;
    return false;
  }
} // our class ends here

    $example = new Divisors(4567893421);
    print $example->countDivisors();
?>