实现计算正整数的数量的函数,该正整数的数量可以被给定数组中的至少一个素数整除

时间:2011-08-24 21:27:21

标签: php c++ algorithm

我真的不知道c ++,但我需要在php中翻译算法。你能帮我吗,特别是不清楚行std :: transform(...

任务是: 实现计算正整数的数量的函数,该正整数的数量可以被给定数组中的至少一个素数整除。调用者将确保此数组已排序且仅包含唯一素数,因此您的实现可能会利用这些假设而不需要 检查它们是否真的存在。

只要除数列表保持相对较短,有一种非常有效的算法可以计算任何n值的这些数字。

#include <algorithm>
#include <functional>
#include <iostream>
#include <ostream>
#include <vector>

std::vector<signed int> gen_products_of_n_divisors(
    const std::vector<signed int>::const_iterator &start,
    const std::vector<signed int>::const_iterator &end,
    signed int n)
{
  if (n == 1)
  {
    return std::vector<signed int>(start, end);
  }
  std::vector<signed int> products;
  for (std::vector<signed int>::const_iterator i = start;
      i != end; ++i)
  {
    std::vector<signed int> sub_products =
        gen_products_of_n_divisors(i + 1, end, n - 1);
    products.resize(products.size() + sub_products.size());
    std::transform(sub_products.begin(), sub_products.end(),
        products.end() - sub_products.size(),
        std::bind1st(std::multiplies<signed int>(), *i));
  }
  return std::vector<signed int>(products);
}

signed int count_divisibles(signed int n,
    const std::vector<signed int> &divisors)
{
  signed int total_count = 0;
  for (signed int i = 1;
      i <= static_cast<signed int>(divisors.size()); ++i)
  {
    std::vector<signed int> products =
        gen_products_of_n_divisors(divisors.begin(),
        divisors.end(), i);
    signed int sign = 2 * (i % 2) - 1;
    for (
        std::vector<signed int>::iterator j =
        products.begin();
        j != products.end(); ++j)
    {
      total_count += sign * n / (*j);
    }
  }
  return total_count;
}

int main()
{
  std::vector<signed int> a;
  a.push_back(3);
  a.push_back(5);
  a.push_back(7);
  a.push_back(11);
  a.push_back(13);
  a.push_back(17);
  a.push_back(19);
  std::cout << count_divisibles(1000000, a) << std::endl;
}

1 个答案:

答案 0 :(得分:0)

如果您熟悉Inclusion–exclusion principle,将更容易理解Toolbox的std :: transform参考及其对子产品(除数组子集成员的乘积)的解释。 }。实际上,作为奇数个数的乘积的子产品增加了除数的总数,而那些是偶数个乘积的子产品从中减去。在下面对C ++程序的C的翻译中,这可能更为明显。

在该计划中,请注意1<<nDiv2^nDiv(其中^表示指数取消)。一组k个元素的幂集中有2^k个子集。每个不同的子集对应于不同的二进制ID#。 (ID#=“身份证号码”)。如果该元素的位在子集的ID#中设置,则set元素是子集的成员。程序将sign从-1切换为1或从1切换到-1以跟踪偶数或奇数位。

一个真实的程序(对比这样的玩具演示)应该在product的最里面的循环中计算count_divisibles()时检查溢出。

// translation to C of C++ program in question
#include <stdlib.h>
#include <stdio.h>

int count_divisibles(int n, int *divisors, int nDiv) {
  int total_count = 0;
  int i, it, j, sign, product;
  for (i=1; i < 1<<nDiv; ++i) {
    product = 1;
    sign = -1;
    for (j=0, it=i; j<nDiv; ++j, it=it/2) {
      if (it & 1) {
        product *= divisors[j];
        sign = -sign;
      }
    }
    total_count += sign * n/product;
  }
  return total_count;
}

int main(void) {
  int a[] = {3,5,7,11,13,17};
  int nDiv = sizeof a / sizeof a[0];
  int hi, c, k;

  for (hi=1000000; hi; hi/=200) {
    for (k=0; k<nDiv; ++k) {
      c = count_divisibles(hi, a, k);
      printf ("count_divisibles(%d, a, %d) = %6d     a[%d]=%d\n",
              hi, k, c, k, a[k]);
    }
    c = count_divisibles(hi, a, nDiv);
    printf ("count_divisibles(%d, a, %d) = %6d\n",  hi, nDiv, c);
  }
  return 0;
}