今天写了一道很有意思的算法题,好久没有写过博客啦,随手记下来~
问题描述 :
有这样一种素数叫纯素数(YY出来的名字),当它是一个多位数的时候,你把它的末位去掉之后余下的数依然是一个素数。比如说2393,2393 本身是一个素数,它的末位去掉之后,余下的是239。239 是一个素数,它的末位去掉之后,余下的是23 。23是一个素数,它的末位去掉之后,余下的是2 。2依然还是一个素数。纯素数的长度叫做“维”。2393 是一个4维素数。3797也是一个4维素数。
输入说明 :
第一行先给出一共有多少组数据N(N<=1000),接下来有N组数据.
每组包括一个整数T(1<=T<=8)。
输出说明 :
按照从小到大的顺序输出所有的T维纯素数。
输入范例 :
3
8
1
4
输出范例:
23399339
29399999
37337999
59393339
73939133
2
3
5
7
2333
2339
2393
2399
2939
3119
3137
3733
3739
3793
3797
5939
7193
7331
7333
7393
这道题拿到手第一个想法就是暴力解法,但是一想比如输入T=8,那么直接从10000000~99999999里面找出来所有符合的质数,显然这样就太耗时了,注意到题目提醒深度优先搜索,于是琢磨一下,写了一个广度优先的思路。
我的思路是从个位开始,逐位判断的方式。因为想要符合“纯素数”的要求,那么个位必然是素数。而1维素数只有2,3,5,7,那么就达到了剪枝的目的。
把1维素数逐个入队,然后开始循环,当队列非空的时候,访问队头,即先取出2,再找所有2开头的的2维素数,依次入队,23,29,访问3,再找所有3开头的2维素数。。。如是这样就省去了很多时间啦。
上代码
#pragma warning(disable:4996)
#include<stdio.h>
#include<math.h>
typedef struct
{
int data[100];//足够大,不构造循环队列了
int front, rear;
}Queue;
int PrimeNumber(int n);
int IsEmptyQ(Queue Q);
int main() {
int n, T, i,temp,min,max;
Queue Q;
while (scanf("%d", &n) != EOF)
{
if (n <= 1000 && n > 0)
{
while (n)
{
scanf("%d", &T);
if (T >= 1 && T <= 8)
{
min = pow(10, T-1);
max = pow(10, T) - 1;
//初始化队列
Q.front = 0, Q.rear = 0;
//开头为1的一定不是素数
for (i = 2; i <= 7; i++)
{
//是素数,入队
if (PrimeNumber(i))
{
Q.data[Q.rear++] = i;
}
}
//队列非空则循环
while (!IsEmptyQ(Q))
{
//队头出队访问
temp = Q.data[Q.front++];
//若符合位数,则输出
if (temp >= min && temp <= max)
{
printf("%d\n",temp);
}
for (i = 1; i <= 9; i++)
{
//是素数则入队
if (PrimeNumber(temp * 10 + i))
{
Q.data[Q.rear++] = temp * 10 + i;
}
}
}
}
n--;
}
}
}
return 0;
}
int PrimeNumber(int n)
{
int i;
for (i = 2; i <= sqrt(n); i++)
{
//不是素数
if (n % i == 0)
{
return 0;
}
}
return 1;
}
int IsEmptyQ(Queue Q)
{
if (Q.front == Q.rear)
{
return 1;
}
else
{
return 0;
}
}