Description
Aring is composed of n (even number) circles as shown in diagram. Put naturalnumbers into each circleseparately, 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 <= 16)
Output
The output format isshown as sample below. Each row represents a series of circle numbers in thering beginning from 1 clockwisely and anticlockwisely. The order of numbersmust satisfy the above requirements.
You are to write a program that completes above process.
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
方法一:
用prime【】判断是否是素数,用permutation函数生成全排列并且判断此排列是否满足条件。生成全排列时我用for循环来判断i是否可以加在排列的尾部,并且在is_prime函数中用循环来判断是否符合条件结果代码超时。代码如下:#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=50+5;
int n,ring[maxn],prime[maxn];
void become(){
memset(prime,0,sizeof(prime));
for(int i=2;i<=maxn;i++){
bool ok=true;
for(int j=2;j<i;j++)
if(i%j==0){
ok=false;
break;
}
if(ok) prime[i]=1;
}
}
void is_prime(int n){
bool ok=true;
for(int i=1;i<=n;i++){
int p=ring[i]+ring[i%n+1];
if(!prime[p]) ok=false;
}
if(ok){
for(int i=1;i<=n;i++) printf("%d ",ring[i]);
printf("\n");
}
}
void permutation(int n,int num){
if(num==n) is_prime(n);
else{
for(int i=2;i<=n;i++){
bool ok=true;
for(int j=2;j<=num;j++)
if(ring[j]==i) ok=false;
if(ok){
ring[num+1]=i;
permutation(n,num+1);
}
}
}
}
int main(){
become();
int count=0;
while(scanf("%d",&n)==1){
memset(ring,0,sizeof(ring));
ring[1]=1;
printf("Case %d:\n",++count);
permutation(n,1);
printf("\n");
}
return 0;
}
方法二:回溯法——在生成全排列是就顺便判断是否符合条件而不是再用另一个函数判断,且判断此数是否出现过时不再使用for循环,而是用vir【】数组做下标记即可,需要注意的是vir【】恢复。代码如下
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=50+5;
int n,ring[maxn],prime[maxn],vir[maxn];
void become(){
memset(prime,0,sizeof(prime));
for(int i=2;i<=maxn;i++){
bool ok=true;
for(int j=2;j<i;j++)
if(i%j==0){
ok=false;
break;
}
if(ok) prime[i]=1;
}
}
void is_prime(int n){
bool ok=true;
for(int i=1;i<=n;i++){
int p=ring[i]+ring[i%n+1];
if(!prime[p]) ok=false;
}
}
void dfs(int num){
if(num==n&&prime[ring[1]+ring[n]]){
for(int i=1;i<=n;i++) printf("%d ",ring[i]);
printf("\n");
}
else{
for(int i=2;i<=n;i++){
if(!vir[i]&&prime[i+ring[num]]){ //判断
vir[i]=1; //做标记
ring[num+1]=i;
dfs(num+1);
vir[i]=0; //恢复
}
}
}
}
int main(){
become();
int count=0;
while(scanf("%d",&n)==1){
memset(vir,0,sizeof(vir));
memset(ring,0,sizeof(ring));
ring[1]=1;
printf("Case %d:\n",++count);
dfs(1);
printf("\n");
}
return 0;
}
因此,通过加标记的方法可以避免使用for循环,同时边加入边判断也是提高效率的方法。
提交了多次都是WA,原因是prime数组开的小了,试想一下,假设n=16,那和最大是16+16=32,而最开始只开到了16。