神奇的丑数

对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S。如质因子2、3和5的数,6、8都是丑数,前20个丑数为:1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36。但7、14不是,因为它们包含质因子7。 习惯上我们把1当做是第一个丑数。

这个正整数集合包括,1、p1、p1*p2、p1*p1、p1*p2*p3...(还有其它)。该集合被称为S集合的“丑数集合”。1是一个丑数,丑数集合中每个数从小到大排列,每个丑数都是素数集合中的数的乘积。请问第20000丑数是多少

#include

#include

#include

// 定义优先队列结构体

typedef struct {

    long long *data;

    int size;

    int capacity;

} PriorityQueue;

// 初始化优先队列

PriorityQueue* createPriorityQueue() {

    PriorityQueue* pq = (PriorityQueue*)malloc(sizeof(PriorityQueue));

    pq->data = (long long*)malloc(100 * sizeof(long long));

    pq->size = 0;

    pq->capacity = 100;

    return pq;

}

// 交换元素

void swap(long long *a, long long *b) {

    long long temp = *a;

    *a = *b;

    *b = temp;

}

// 上浮操作

void upHeapify(PriorityQueue* pq, int index) {

    while (index > 0 && pq->data[(index - 1) / 2] > pq->data[index]) {

        swap(&pq->data[(index - 1) / 2], &pq->data[index]);

        index = (index - 1) / 2;

    }

}

// 下沉操作

void downHeapify(PriorityQueue* pq, int index) {

    int left = 2 * index + 1;

    int right = 2 * index + 2;

    int smallest = index;

    if (left < pq->size && pq->data[left] < pq->data[smallest]) {

        smallest = left;

    }

    if (right < pq->size && pq->data[right] < pq->data[smallest]) {

        smallest = right;

    }

    if (smallest != index) {

        swap(&pq->data[index], &pq->data[smallest]);

        downHeapify(pq, smallest);

    }

}

// 插入元素

void enqueue(PriorityQueue* pq, long long value) {

    if (pq->size == pq->capacity) {

        pq->capacity *= 2;

        pq->data = (long long*)realloc(pq->data, pq->capacity * sizeof(long long));

    }

    pq->data[pq->size] = value;

    upHeapify(pq, pq->size);

    pq->size++;

}

// 弹出最小元素

long long dequeue(PriorityQueue* pq) {

    if (pq->size == 0) {

        return -1; // 错误处理

    }

    long long minValue = pq->data[0];

    pq->size--;

    pq->data[0] = pq->data[pq->size];

    downHeapify(pq, 0);

    return minValue;

}

// 释放优先队列

void freePriorityQueue(PriorityQueue* pq) {

    free(pq->data);

    free(pq);

}

int main() {

    int primes[] = {3, 7, 17, 29, 53};

    int numPrimes = sizeof(primes) / sizeof(primes[0]);

    PriorityQueue* pq = createPriorityQueue();

    enqueue(pq, 1);

    long long uglyNumber;

    bool* visited = (bool*)calloc(10000000, sizeof(bool)); // 标记已经计算过的丑数

    visited[1] = true;

    for (int i = 0; i < 20220; i++) {

        uglyNumber = dequeue(pq);

        for (int j = 0; j < numPrimes; j++) {

            long long newUgly = uglyNumber * primes[j];

            if (!visited[newUgly]) {

                visited[newUgly] = true;

                enqueue(pq, newUgly);

            }

        }

    }

    printf("第20000个丑数是: %lld\n", uglyNumber);

    freePriorityQueue(pq);

    free(visited);

    return 0;

}

1. 优先队列实现:通过自定义结构体和相关函数实现了一个小顶堆结构的优先队列,用于存储丑数并保证每次取出的是最小的丑数。

2. 计算丑数:从初始丑数  1  开始,每次取出当前最小丑数,然后乘以素数集合中的每个素数得到新的丑数,将新的未访问过的丑数加入优先队列。

你可能感兴趣的:(c语言)