素数环
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
2
-
描述
-
有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻两个数(包括首尾)的和都为素数,称为素数环。
为了简便起见,我们规定每个素数环都从1开始。例如,下图就是6的一个素数环。
-
输入
- 有多组测试数据,每组输入一个n(0<n<20),n=0表示输入结束。 输出
-
每组第一行输出对应的Case序号,从1开始。
如果存在满足题意叙述的素数环,从小到大输出。
否则输出No Answer。
样例输入
-
6 8 3 0
样例输出
-
Case 1: 1 4 3 2 5 6 1 6 5 2 3 4 Case 2: 1 2 3 8 5 6 7 4 1 2 5 8 3 4 7 6 1 4 7 6 5 8 3 2 1 6 7 4 3 8 5 2 Case 3: No Answer
这个题开始交了三四遍都是超时= =.改着改着居然又改成WA了.....
我觉得素数环有一个关键的地方在于 如果输入N是奇数的话,由于起点从1开始,那么1-N之间一共有N / 2个偶数,N / 2 +1个奇数,也就是奇数的个数比偶数多一个,那么把这N个数排成一个环,必然有两个奇数是相邻的,而两个奇数之和是偶数,偶数不是素数,所以我们得出结论,.这样当N是奇数的时候,直接输出no answer. 还有一点 1也是素数环.
做题的时候我还犯了一个错误....n虽然最大只有19, 但是,素数判断最大是19+18 = 37, 而我刚开始只把记录素数的数组开到了20....所以后面出错了,不太应该.
剩下的就是dfs了.因为第一个数是1,所以我在初始化数组的时候就把0位置置成1了,选数字的时候直接从2开始选就可以.
素数环有一个特点,那就是相邻两个数的奇偶性一定不同,因为奇数加上奇数等于偶数,偶数加上偶数也是偶数,而偶数一定不是素数,所有也可以在选取这一元素的时候跟上一元素比较下奇偶性,如果奇偶性相同,那么直接跳过.
#include<stdio.h>
#include <string.h>
#define SIZE 40
int x;
bool flag;
bool prime [SIZE];
bool vis[SIZE];
int ans[SIZE];
void isprime ()
{//素数筛选法 是素数置0 不是置1
int i, j;
prime[0] = prime[1] = 1;
prime[2] = 0;
for(i = 2; i * i <= SIZE; i++)
{
if(!prime[i])
{
for(j = i + i; j <= SIZE; j += i)
{
prime[j] = 1;
}
}
}
}
void dfs(int cur)
{
int i;
if(cur == x && !prime[ans[cur - 1] + ans[0]])
{//以为是环, 所以不要忘记判断第一个数和最后一个数相加是否也是素数
flag = 1;
for(i = 0; i < cur; i++)
{
printf("%d ", ans[i]);
}
printf("\n");
}
else
{
for(i = 2; i <= x; i++)
{
if(!vis[i] && !prime[ans[cur - 1] + i])
{
vis[i] = 1;
ans[cur] = i;
dfs(cur + 1);
vis[i] = 0;
}
}
}
}
int main (void)
{
isprime();
int n = 1;
while (scanf("%d", &x))
{
if(x == 0)
return 0;
flag = 0;
memset(vis, 0, sizeof(vis));
memset(ans, 0, sizeof(ans));
ans[0] = 1;
printf("Case %d:\n", n++);
if(x % 2 == 0 || x == 1)//如果是偶数或者是1才进行深搜,是奇数,直接no answer
dfs(1);
if(flag == 0)
{
printf("No Answer\n");
}
}
return 0;
}