Prime Ring Problem
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 36882 Accepted Submission(s): 16249
Problem Description
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.
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.
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开始,那么1-N之间一共有N / 2个偶数,N / 2 + 1个奇数,也就是奇数的个数比偶数多一个,那么把这N个数排成一个环,根据鸽巢原理,必然有两个奇数是相邻的,而两个奇数之和是偶数,偶数不是素数,所以我们得出结论,如果输入N是奇数的话,没有满足条件的排列。这样当N是奇数的时候,直接返回可。如果1-N之间每个数输入的几率相同,这个判断可以减少一半的计算量。再扩展一下,可以发现,任何一个满足条件的排列都有一个共同点:相邻的两个数奇偶性必然不同,原因是:两个奇数之和或者两个偶数之和都是偶数,而偶数一定不是素数,所以在选取当前元素的时候,比较一下它和前一个元素的奇偶性。再做决定,可以减少一部分计算量。由 于奇数 + 偶数 = 奇数, 而奇数的二进制表示中,最低位是1, 所以有下面的代码, 其中curValue是当前值, a[lastIndex]是前一个值.
#include<stdio.h>
#include<stdlib.h>
int prime[38]{ //巧妙的应用
0,0,1,1,0,1,0,1,0,
0,0,1,0,1,0,0,0,1,
0,1,0,0,0,1,0,0,0,
1,0,1,0,1,0,0,0,0,
0,1
};
bool isok(int a[], int lastIndex, int curValue){
//if( lastIndex < 0 )//完全没必要判断,因为不可能小于零
// return true;
if(!prime[a[lastIndex]+curValue]) //判断相邻两个数的和是否为素数
return false;
if(!((a[lastIndex]+curValue)&1)) //判断相邻两个数的奇偶性
return false;
for(int i=0; i<=lastIndex; ++i){ //判重
if(a[i]==curValue)
return false;
}
return true;
}
void output(int a[], int n){
for(int i=0; i<=n-1; ++i){
if(i==n-1)
printf("%d",a[i]);
else
printf("%d ",a[i]);
}
printf("\n");
}
void cyclePrime(int a[], int n, int k){
if(n&1)
return;
if(k==n){
if(prime[a[0]+a[n-1]]) //并且首尾也满足相加为素数,输出
output(a,n);
}
else{
for(int i=2;i<=n;++i){
a[k]=i;
if(isok(a,k-1,i))
cyclePrime(a,n,k+1);
}
}
}
int main(){
int n,m=0;
while(scanf("%d",&n)==1){
int a[25];
a[0]=1;
printf("Case %d:\n",++m);
cyclePrime(a,n,1);
printf("\n");
}
return 0;
}