题目描述
OJ地址 http://lx.lanqiao.cn/problem.page?gpid=T33
幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的“筛法”生成。
首先从1开始写出自然数1,2,3,4,5,6,…
1 就是第一个幸运数。
我们从2这个数开始。把所有序号能被2整除的项删除,变为:
1 _ 3 _ 5 _ 7 _ 9 …
把它们缩紧,重新记序,为:
1 3 5 7 9 … 。这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被3整除!! 删除的应该是5,11, 17, …
此时7为第3个幸运数,然后再删去序号位置能被7整除的(19,39,…)
最后剩下的序列类似:
1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, …
输入:
输入两个正整数m n, 用空格分开 (m < n < 1000*1000)
输出:
程序输出 位于m和n之间的幸运数的个数(不包含m和n)。
样例输入1:
1 20
样例输出1:
5
样例输入2:
30 69
样例输出2:
8
思路:
弄一个链表,把1到m之间的数,每个数做一个节点,然后再考虑删除的操作,链表的删除,删除最后一个节点的时候要考虑周到一些,为了方便,链表我用的双向链表。
记录当前的幸运数luck和当前幸运数在第index个节点上。依次遍历每个链表中的每个节点,如果遍历第 i 个节点时,i(节点的序号)是luck的整数倍,那就删除这个节点。
删除完毕后,新的幸运数也就出现了,index后移一位就是新的幸运数所在的节点序号,遍历到第index++个节点,就可以取到新的幸运数luck。然后判断luck是否满足 大于 n 小于 m,满足的话就计数,否则再判断一下幸运数是不是链表的最后一个节点了,如果是的话,就结束所有的循环吧。因为整个链表长度为m,最后一个数是m,幸运数也不可能大于等于m,所以一定在m以内,一翻操作之后,不是幸运数的都删没了,所以一个幸运数的后边如果是NULL(没有节点了),那就不用再进行删除操作了,所有的幸运数都已经找到(链表中的节点都是幸运数)。
代码
#include <bits/stdc++.h>
using namespace std;
int ans[1005];
struct node{
int data;
node* next;
node* pre;
};
node* creatlist(int n){
// 双向链表
node *head,*tail,*cur;
head = (node *)malloc(sizeof(node));
tail = head;
for(int i = 0; i < n-1; i++){
// 除去head 还有n-1个节点
cur = (node *)malloc(sizeof(node));
tail -> next = cur;
cur -> pre = tail;
tail = cur;
}
tail -> next = NULL;
return head;
}
int main(){
int n,m,ans = 0;
cin >> n >> m;
node *list = creatlist(m); //最长就m个节点够了 幸运数 < m
node *tmp = list;
for(int i = 1; i <= m; i++){
tmp -> data = i;
tmp = tmp -> next;
}
node *cur = list -> next; //从第二个节点开始
int luck = 2; //当前的幸运数 (要删除的下标) 2其实并不是幸运数,但是这里以2开始删除
int index = 1; //幸运数在第几个节点上
while(1){
// 从第二个节点开始操作 因为第一个节点是1
for(int i = 2; cur != NULL ; i++){
// 第i个节点
if(i % luck == 0){
// 删除该节点
if(cur -> next == NULL){
// 删除为节点要注意
cur -> pre -> next = NULL; //倒数第二个节点为尾节点
free(cur);
cur = NULL;
}
else{
cur -> pre -> next = cur -> next;
cur -> next -> pre = cur -> pre;
node *t = cur -> next;
free(cur);
cur = t;
}
}else{
cur = cur -> next;
// 检查下一个节点
}
}
//删除完毕 幸运数下标后移一位,得到新的幸运数的位置(当前幸运数在第几个节点上)
index++;
tmp = list; // 从链表头开始
for(int i = 0 ; i < index;i++){
//获取当前的幸运数
if(tmp != NULL){
luck = tmp -> data;
tmp = tmp -> next;
}
}
cur = list -> next; // 恢复指针 准备下一次的while循环 从第2个节点开始
if(luck > m){
break;
}else if(luck > n && luck < m){
// 在n和m之间 不包括 n和m 计数
ans++;
}
if(tmp == NULL){
// 幸运数是 最后一个节点 代表所有的节点都考虑过了 跳出while
break;
}
}
cout << ans << endl;
return 0;
}