获取仅除以2,3和/或5的数字,但不得除以任何其他素数

时间:2012-09-16 21:28:11

标签: c++ math

我得到一个整数N,我必须找到前面只有2,3和/或5可以除的N个元素,而不是任何其他素数。

例如:

N = 3
Results: 2,3,4
N = 5
Results: 2,3,4,5,6

错误编号= 55..55 / 5 = 11..11这是一个素数。由于55..55可以被不同于2,3和5的素数除,所以它不算数。

我想我需要一个递归函数,但我无法想象算法会是什么样子

4 个答案:

答案 0 :(得分:2)

只能被2,3或5整除的唯一数字是权力2 i ×3 j ×5 k i j k = 0,1 ,....

这些数字很容易生成。

答案 1 :(得分:2)

您要搜索的数字的格式为2^n * 3^m * 5^k,其中n,m和k为正整数,n+m+k > 0

我预先生成一个已排序的数组,然后打印出第一个N

答案 2 :(得分:2)

我们可以通过合并汉明数列的适当倍数来有效地生成序列,即经典算法。

如果n > 1是可被p整除的汉明号码,则n/p也是汉明号码,如果m是汉明号码且p 2,3或5中的一个,然后m*p也是汉明数字。

所以我们可以将汉明数的序列描述为

H = 1 : (2*H ∪ 3*H ∪ 5*H)

其中p*H是通过将所有汉明数乘以p获得的排序序列,表示已排序的联合(因此使用H = 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ...,例如2*H = 2, 4, 6, 8, 10, 12, 16, 18, 20, 24, ... }和2*H ∪ 3*H = (2, 4, 6, 8, 10, 12, 16, ...) ∪ (3, 6, 9, 12, 15, ...) = (2, 3, 4, 6, 8, 9, 10, 12, 15, 16, ...))。

但该算法有两个缺点。首先,它产生必须在合并()步骤中消除的重复项。其次,要生成N附近的汉明数字,需要知道N/5N/3N/2附近的汉明数字,最简单的方法是保持内存中N/5N之间序列的一部分,对于大型N需要相当多的内存。

解决这两个问题的变体以5的幂序列开始,

P = 1, 5, 25, 125, 625, 3125, ...

并且在第一步中产生没有素数因子的数字,除了3或5,

T = P ∪ 3*T   (= 1 : (5*P ∪ 3*T))

(除了3和5之外没有素因子的n是5的幂(n ∈ P),或者它可以被3整除,n/3也没有素因子除了3和5(n ∈ 3*T))。显然,序列P3*T是不相交的,因此这里不会产生重复。

然后,最后我们通过

获得汉明数的序列
H = T ∪ 2*H

同样,很明显不会产生重复项,并且要在N附近生成汉明数字,我们需要知道T附近的序列N,这需要知道{{} 1}} P附近的NT附近的N/3以及H附近的序列N/2。在HN/2之间只保留N的部分,在TN/3之间保留N的部分需要更少的空间而不是将HN/5之间的部分保留在记忆中。

my Haskell code到C ++的粗略翻译(毫无疑问,但是我几乎没有写过C ++,我学到的C ++很古老)产生

N

这样做的工作没有太低效:

#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <gmpxx.h>

class Node {
public:
    Node(mpz_class n) : val(n) { next = 0; };
    mpz_class val;
    Node *next;
};

class ListGenerator {
public:
    virtual mpz_class getNext() = 0;
    virtual ~ListGenerator() {};
};

class PurePowers : public ListGenerator {
    mpz_class multiplier, value;
public:
    PurePowers(mpz_class p) : multiplier(p), value(p) {};
    mpz_class getNext() {
        mpz_class temp = value;
        value *= multiplier;
        return temp;
    }
    // default destructor is fine here
    // ~PurePowers() {}
};

class Merger : public ListGenerator {
    mpz_class multiplier, thunk_value, self_value;
    // generator of input sequence
    // to be merged with our own output
    ListGenerator *thunk;
    // list of our output we need to remember
    // to generate the next numbers
    // Invariant: list is never empty, and sorted
    Node *head, *tail;
public:
    Merger(mpz_class p, ListGenerator *gen) : multiplier(p) {
        thunk = gen;
        // first output would be 1 (skipped here, though)
        head = new Node(1);
        tail = head;
        thunk_value = thunk->getNext();
        self_value = multiplier;
    }
    mpz_class getNext() {
        if (thunk_value < self_value) {
            // next value from the input sequence is
            // smaller than the next value obtained
            // by multiplying our output with the multiplier
            mpz_class num = thunk_value;
            // get next value of input sequence
            thunk_value = thunk->getNext();
            // and append our next output to the bookkeeping list
            tail->next = new Node(num);
            tail = tail->next;
            return num;
        } else {
            // multiplier * head->val is smaller than next input
            mpz_class num = self_value;
            // append our next output to the list
            tail->next = new Node(num);
            tail = tail->next;
            // and delete old head, which is no longer needed
            Node *temp = head->next;
            delete head;
            head = temp;
            // remember next value obtained from multiplying our own output
            self_value = head->val * multiplier;
            return num;
        }
    }
    ~Merger() {
        // delete wrapped thunk
        delete thunk;
        // and list of our output
        while (head != tail) {
            Node *temp = head->next;
            delete head;
            head = temp;
        }
        delete tail;
    }
};

// wrap list generator to include 1 in the output
class Hamming : public ListGenerator {
    mpz_class value;
    ListGenerator *thunk;
public:
    Hamming(ListGenerator *gen) : value(1) {
        thunk = gen;
    }
    // construct a Hamming number generator from a list of primes
    // If the vector is empty or contains anything but primes,
    // horrible things may happen, I don't care
    Hamming(std::vector<unsigned long> primes) : value(1) {
        std::sort(primes.begin(), primes.end());
        ListGenerator *gn = new PurePowers(primes.back());
        primes.pop_back();
        while(primes.size() > 0) {
            gn = new Merger(primes.back(), gn);
            primes.pop_back();
        }
        thunk = gn;
    }
    mpz_class getNext() {
        mpz_class num = value;
        value = thunk->getNext();
        return num;
    }
    ~Hamming() { delete thunk; }
};

int main(int argc, char *argv[]) {
    if (argc < 3) {
        std::cout << "Not enough arguments provided.\n";
        std::cout << "Usage: ./hamming start_index count [Primes]" << std::endl;
        return 0;
    }
    unsigned long start, count, n;
    std::vector<unsigned long> v;
    start = strtoul(argv[1],NULL,0);
    count = strtoul(argv[2],NULL,0);
    if (argc == 3) {
        v.push_back(2);
        v.push_back(3);
        v.push_back(5);
    } else {
        for(int i = 3; i < argc; ++i) {
            v.push_back(strtoul(argv[i],NULL,0));
        }
    }
    Hamming *ham = new Hamming(v);
    mpz_class h;
    for(n = 0; n < start; ++n) {
        h = ham->getNext();
    }
    for(n = 0; n < count; ++n) {
        h = ham->getNext();
        std::cout << h << std::endl;
    }
    delete ham;
    return 0;
}

(Haskell版本更快,GHC可以优化惯用的Haskell,而不是优化单一的C ++)

答案 3 :(得分:0)

总是有蛮力的方式:

int[] A = int[N];
int i=0;
int j=2;
while(i<N)
{
    if(j%2==0)
    {
        if(j/2==1 || A contains j/2)
        {
             A[i]=j;
             i++;
        }
    }
    else if(j%3==0)
    {
        if(j/3==1 || A contains j/3)
        {
             A[i]=j;
             i++;
        }
    }
    else if(j%5==0)
    {
        if(j/5==1 || A contains j/5)
        {
             A[i]=j;
             i++;
        }
    }
    j++;
}

对于“A contains X”部分,您可以在范围0到i-1中使用二进制搜索,因为A在那里排序。