素数环


时间限制:1000 ms  |  内存限制:65535 KB


难度:2

描写叙述

有一个整数n,把从1到n的数字无反复的排列成环,且使每相邻两个数(包含首尾)的和都为素数,称为素数环。

为了简便起见,我们规定每一个素数环都从1開始。比如,下图就是6的一个素数环。

 

输入 有多组測试数据,每组输入一个n(0<n<20),n=0表示输入结束。 输出 每组第一行输出相应的Case序号,从1開始。

假设存在满足题意叙述的素数环,从小到大输出。

否则输出No Answer。 例子输入

6
8
3
0

例子输出

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
Case 3:
No Answer

 道题应该算是比較简单的题了,提交了好几次都是TLE,我就郁闷了。。。看来基础还是不扎实啊。。。最后用素数的哈希表最终AC了。。。先前是各种TLE,程序优化真的非常重要啊。这就是算法的魅力所在~

#include <stdio.h>
#include <string.h>
#define MAXN 40
int A[MAXN];
int vis[MAXN];
int n;
int isprime[40]={
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,0,
};//素数的哈希表,1代表就是素数
void dfs(int cur)//搜索+回溯(回溯事实上也是依据树的深度搜索来的)
{
int i;
if(cur==n && isprime[A[0]+A[n-1]])//递归边界,对第一个和最后一个数进行測试
{
for(i=0;i<n;i++)
printf("%d ",A[i]);
printf("\n");
}
else for(i=2;i<=n;i++)//尝试放置每个数
if(!vis[i] && isprime[i+A[cur-1]])//先看这个数有没有被标记,然后看与前面的一个数的和是否为素数
{
A[cur]=i;
vis[i]=1;//标记搜索过的路径
dfs(cur+1);
vis[i]=0;//清除标记 ,回溯
}
}
int main()
{
int i,j;
int k=1;
while(scanf("%d",&n)&&n!=0)
{
memset(vis,0,sizeof(vis));//初始化vis数组
for(i=0;i<n;i++)
A[i]=i+1;
printf("Case %d:\n",k++);
if(n==1)//自成环
{
printf("1\n");
continue;
}
if(n%2!=0)//剪枝,假设n为奇数不可能成环
{
printf("No Answer\n");
continue;
}
dfs(1);
}
return 0;
}


这里我应该还是钻了空子,还是不太严谨,20一类的偶数都可以成素数环,大于20就不一定了,还是有待改进啊。。


本来是想用筛选发筛选出素数的,各种TLE啊。。。  (感觉筛选法效率挺高的啊)

for(i=2;i<=MAXN;i++)
{
isprime[0]=isprime[1]=1;
if(isprime[i]==0)
for(j=i+i;j<MAXN ;j+=i)
isprime[j]=1;
}