Prime Ring Problem
A ring is compose of n circles as shown in diagram. Put natural number 1, 2, …, n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.
Note: the number of first circle should always be 1.
Input
n (0 < n < 20).
Output
The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.
You are to write a program that completes above process.
Print a blank line after each case.
Sample Input
6
8
Sample Output
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
题意
已知一个数n,将数字1~n围成一个圆环,要求: 相邻两个数之和为素数。
输出:
- 数字的方向一致(同顺时针或同逆时针),并保证排列不重复
- 只有一个数(n==1)时,输出1
- 输出Case k:(k为数据组数),每一组输出(第一个除外)之前都有一个空行
思路:
- 要求每两个相邻数之和都为素数,那么只要每次递归调用DFS时判断之前两个数之和是否为素数,另外注意因为是一个环,最后还要判断一下最后一个数和第一个数之和是否为素数。
- 程序开始时求出一个素数数组,只需求出50以内的素数即可,因为数据<20,最大的素数和为17+19=36。此处用的是素数筛法(什么是素数筛法?)求素数。
素数筛法概览:
- 把从1开始的、某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。依次类推,直到筛子为空时结束
- 例如: 先把n个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数
代码示例:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAX 51
using namespace std;
int prime[MAX];//素数数组
bool vis[21]; //访问数组
int n;// 个数
int ans[21];//解答输出数组
void Prime_set() //筛法求素数
{
//Isprime 0、 IsNotprime 1
for(int i = 2; i<=sqrt(MAX) ;++ i)
if(prime[i] == 0){
for(int j = 2;i*j<=MAX;++j)
prime[i*j] = 1;
}
prime[1] = 0,vis[1]=true;//1虽然不是素数,但在此假设为0,将vis[1]设为true即不会遍历到1
}
void DFS(int depth)
{
if(prime[ans[depth-1]+ans[depth-2]]!=0) return ; //前两个数之和不是素数退出
if(depth==n+1&&prime[ans[depth-1]+ans[1]]!=0) return ; //当选到最后一个数时,第一个数和最后一个数之和不是素数时退出
if(depth==n+1) //选到最后一个数,输出
{
for(int i=1;i<=n;i++)
{
if(i==1) cout<<ans[i];
else cout<<" "<<ans[i];
}
cout<<endl;
}
for(int i=2;i<=n;i++) //把1~n按照一定顺序(DFS求得)填入数组ans
{
if(!vis[i])
{
vis[i]=true;
ans[depth]=i;
DFS(depth+1);
vis[i]=false;
}
}
}
int main(){
int t=1;
Prime_set();
while(cin>>n)
{
cout<<"Case "<<t++<<":"<<endl;
memset(vis,false,sizeof(vis));
ans[1] = 1;//1永远是首元素
if(n==1) cout<<"1"<<endl;
else
DFS(2);//1永远是首元素,从2开始DFS ;也防止之后depth-2<0
cout<<endl;
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
注:
- Q:1不是素数,为何要prime[1] = 0?
- A:1虽然不是素数,但在此假设为0。因为之后判断(判断两个相邻素数和的时候)会出现一些问题:
if(prime[ans[depth-1]+ans[depth-2]]!=0)
在主函数初始进入DFS(2)时,这一句之中的depth-2等于0,ans[0]不在讨论范围之中,故仍然为0,而ans[1]为1,ans[depth-1]+ans[depth-2]=1,prime[1]如果不等于0的话,将会直接return。
- A:1虽然不是素数,但在此假设为0。因为之后判断(判断两个相邻素数和的时候)会出现一些问题: