跟素数筛法很像,主要是标记和识别(忽略)标记,直接两层for循环水过,也就171毫秒,不过要注意数组的大小,太大没必要,还占时间。
看某神的分类是“链表”。。。。。。开始就是看了分类定向思维用链表做,调BUG吐了口老血,然后实在不想调了,两层for就够了。。。。。。
但是如果数据量再大的话,for很容易超时,链表还是比较优化的算法,但是对于此数据量没必要。
#include <stdio.h>
#include <string.h>
#define N 33850 ///卡一卡大小,使用尽量少的空间,也减少扫描的区间
int a[33860];
int b[3010];
int main()
{
int i, j, cou, cc, c;
memset(a, 0, sizeof(a)); ///初始化标记数组
cc = 0;
for (i = 2; i <= N; i++) {
if (!a[i]) { ///找到排头的
b[++cc] = i; ///记录lucky number
cou = i;
c = 0;
for (j = i; j <= N; j++) {
if (!a[j] && i != j) { ///注意第一次扫的时候不c++
c++;
if (c == cou) {
a[j] = 1; ///标记,说明被派去刷碗,以后扫描时忽略ta
c = 0; ///注意重置计数器
}
}
}
}
}
int n;
while (~scanf("%d", &n) && n) {
printf("%d\n", b[n]);
}
return 0;
}
后来用链表提交的代码,跑了60多毫秒,内存耗得差不多快两倍,以前写链表习题的时候总是习惯性的把不用的节点free掉,但是想到OJ在申请的一瞬间已经达到最大内存空间了,再free就是给自己找事了。代码长度也没有差多少,还是觉得两层for比较好,其实也就是储存方式不一样,但是对数组比较好操作。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 33850
struct node {
int num;
struct node *next;
};
int sizen = sizeof(node);
int b[3010];
int main()
{
#if 0 ///
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif // 1
node *head = NULL, *tail = NULL, *p = NULL;
int i;
for (i = 2; i <= N; i++) { ///从2开始,创建链表
p = (node *)malloc(sizen);
p->num = i;
p->next = NULL;
if (head == NULL) {
head = p;
tail = head;
} else {
tail->next = p;
tail = tail->next;
}
}
int cou = 0, cc = 0;
node *pre = NULL;
for (p = head; p != NULL; head = head->next, p = head) {
b[++cc] = p->num; ///将第一个没有被派去刷碗的记录下来
cou = p->num; ///记录此人的编号,用于循环
while (1) {
for (i = 1; i <= cou; i++) {
pre = p;
p = p->next;
if (p == NULL) break; ///此处很重要,一个循环没跑完就到头了
}
if (p == NULL) ///到头了跳出
break;
else {
pre->next = p->next; ///派去刷碗
free(p);
p = pre; ///注意等于前一个
}
}
}
int n;
while (~scanf("%d", &n) && n) {
printf("%d\n", b[n]);
}
return 0;
}