第一种:DFS法
#include<stdio.h>
int num[21],mark[21],n;int prime_num[12]={2,3,5,7,11,13,17,19,23,29,31,37};
int is_prime(int a)
{
for(int i=0;i<12;i++)
if(a==prime_num[i])
return 1;
return 0;
}
void print_num()
{
for(int i=1;i<n;i++)
printf("%d ",num[i]);
printf("%d",num[n]);
}
int dfs(int pre,int post,int flag)
{
//如果不符合,直接返回
if(!is_prime(pre+post))
return 0;
num[flag]=post;
if(flag==n&&is_prime(post+1))//判断长度是否达到n且最后一个数加上环的起点1是否是素数
{
print_num();
printf("\n");
return 1;
}
mark[post]=0;//把这个数字标记成0表示已经用过了
for(int i=2;i<=n;i++)//开始搜索下一位
if(mark[i]!=0&&dfs(post,i,flag+1))
break;
mark[post]=1;//标记位回复原状,因为没用上
return 0;
}
int main()
{
int ca=1;
while(scanf("%d",&n)!=EOF&&n)
{
printf("Case %d:\n",ca++);
for(int i=1;i<=n;i++)
mark[i]=1;//初始化标记数组
num[1]=1;
if(n==1)
printf("1\n");
else if(n%2)//不存在长度大于1的奇数环
printf("No Answer\n");
else
{
for(int i=2;i<=n;i++)
dfs(1,i,2);//(前面的数,之后的数,序数(长度))
}
}
return 0;
}
第二种 回溯法
#include<iostream>
#include<string.h>
#define N 25
#define M 40
using namespace std;
bool is_prime[M],Visited[N];
int n,test,ans[N];
bool prime(int n)
{
if(n==1) return false;
if(n==2||n==3) return true;
int i;
for(i=2;i<n;i++)
if(n%i==0)
return false;
return true;
}
void work(int k)
{
int i;
if(k==n+1)//搜索到了足够的元素,结束并输出。
{
if(!is_prime[ans[n]+ans[1]])
return ;
for(i=1;i<=n-1;i++)
cout<<ans[i]<<" ";
cout<<ans[i]<<endl;
return;
}
for(i=2;i<=n;i++)
{
if(!Visited[i]&&is_prime[ans[k-1]+i])
{
Visited[i]=true;//把这个数字标记成true表示已经用过了
ans[k]=i;
work(k+1);
Visited[i]=false;//标记恢复原状,因为没用上
}
}
}
int main()
{
int i;
test=1;
for(i=1;i<M;i++) is_prime[i]=prime(i);
while(cin>>n)
{
ans[1]=1;
memset(Visited,false,sizeof(Visited));
cout<<"Case "<<test<<":"<<endl;
work(2);
test++;
cout<<endl;
}
return 0;
}