对于一给定的素数集合 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 开始,每次取出当前最小丑数,然后乘以素数集合中的每个素数得到新的丑数,将新的未访问过的丑数加入优先队列。