给出一个num(0<num<20),在1~num的所有排列中,满足相邻两个数之和是素数(头尾相邻)的排列输出:
我的思路是:排列用递归,然后对一个排列进行扫描,处理。。
代码如下:(问题是递归中出现了错误,不明白为什么)
#include<iostream>
#include<cmath>
using namespace std;
static int count=0;
bool Prime(int m) //判断是否是素数
{
int p=(int)sqrt((double)m);
for(int i=2;i<=p;i++)
if(m%i==0)
return false;
return true;
}
inline void Swap(int a,int b) //两数交换
{
int temp;
temp=a;a=b;b=temp;
}
void Perm(int *ary,int k,int m) //递归求所有排序
{
if(k==m) //递归边界条件
{
bool temp=true;
for(int i=0;i<m;i++)
if(!Prime(ary[i]+ary[i+1]))
{ temp=false;break;}
if(Prime(ary[0]+ary[m])&&temp)
for(int j=0;j<m;j++)
cout<<ary[j]<<' ';
cout<<ary[m]<<endl;
}
else
{
for(int optr=k;optr<=m;optr++)
{
Swap(ary[k],ary[optr]);
Perm(ary,k+1,m);
Swap(ary[k],ary[optr]);
}
}
return ;
}
int main()
{
int ary[21];
int num;
while(cin>>num)
{
if(num<1||num>19)
break;
count++;
cout<<"Case "<<count<<":"<<endl;
for(int i=0;i<num;i++)
ary[i]=i+1;
Perm(ary,0,num-1);
}
return 0;
}
更快的方法是,一边排列,一边扫描,如果当前排列不满足条件,那么即可省略余下的排列。比如1-10的排列,当排到12345的时候,因为4+5=9,非素数,后面就不用再排了,直接到12346,仍然不行,那么就123457,还是不行,然后123458,OK,如此反复直到找到一个候选解。用回溯应该可以。
dfs,
#include <stdio.h>
#include <string.h>
bool prime[45]={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,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0};
int n;
int visted[22],num[22];
void dfs(int count){
if(count==n+1&&prime[num[n]+num[1]]){
for(int i=1;i<=n;++i)
printf("%d ",num[i]);
printf("\n");
}
else for(int i=2;i<=n;++i)
if(!visted[i]&&prime[i+num[count-1]]){
visted[i]=1; num[count]=i;
dfs(count+1);visted[i]=0;
}
}
int main(){
int k=0;
while(scanf("%d",&n),n){
printf("Case %d:\n",++k);
if(n==1)printf("1\n");
else if(n%2){printf("No Answer\n");}
else{
memset(visted,0,sizeof(visted));
num[1]=1;dfs(2);
}
}
return 0;
}