问题链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=488
素数环
时间限制: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
问题分析:
当n=1时,答案为1
当n为奇数时,一定无解。因为n为奇数,则必有两个奇数会相邻(偶数必奇数少,不能把所有奇数用偶数分割开),则和为偶数,偶数一定不是素数(除了2)。因此一定找不到一个序列满足素数环。
当n为偶数时,采用深度搜索的方法,第一个环始终填1,从第二个环开始,每个环都尝试其余的n-1个数字,利用递归对所有情况进行遍历。再遍历时利用相邻两环之和为素数进行剪枝,当深度达到n时,即最后一个环也填了之后,进行判断是否最后一个和第一个环之和为素数。是则进行输出,否则返回上层即可。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#define MAX 21
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int circle[MAX];
int mark[MAX]; //标记数字是否已经使用过
int n; //素数环的大小
int prime[MAX]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,
53, 59, 61 ,67 ,71 }; //预先存储素数
int length = 20; //素数的个数
bool isPrime(int x) {
for(int i=0;i<length;i++){
if(x == prime[i]) {
return true;
}
}
return false;
}
void dfs(int k) {
//printf("%d\n",k);
if(k == n){
if(isPrime(circle[0]+circle[k-1])== false){
return;
}
//进行输出
int i;
for(i=0;i<n-1;i++) {
printf("%d ",circle[i]);
}
printf("%d",circle[i]);
printf("\n");
return;
}
for(int i=2;i<=n;i++){
if(mark[i] == false && isPrime(circle[k-1]+i)){
mark[i] = true;
circle[k] = i;
dfs(k+1);
//递归返回时要重置数字i为未使用
mark[i] = false;
}
}
}
int main(int argc, char** argv) {
int ca = 1;
while(scanf("%d",&n)) {
printf("Case %d:\n",ca++);
if(n%2 == 0){
circle[0]=1;
memset(mark,false,sizeof(mark));
dfs(1) ;
}else if(n == 1){
//不存在偶数个素数的素数环
printf("1\n");
}else{
printf("No Answer\n");
}
}
return 0;
}