nyoj488 素数环

                         素数环

时间限制:1000 ms | 内存限制:65535 KB
难度:2
描述
有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻两个数(包括首尾)的和都为素数,称为素数环。

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

输入
有多组测试数据,每组输入一个n,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

根据题意,要求输出的每两个相邻的数的和为素数,且首尾相连的两个数的和也为素数。因为奇数和奇数相加不会是素数,偶数和偶数相加也不会是素数,所以想要输出满足题意的素数环就必须是奇偶相邻,所以n必须为偶数,但如果输入的n为1则输出为1。不知道我说的够不够明白,在代码中解释。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
#define maxn 22
int prime[110];//存放素数的数组
int a[maxn];//储存并更新排序后的数的序列
int visit[maxn];//用来记录第i个位置是否已经放置好位置
int cur;//代表当前所判断的数是第几个数
int n;
void isprime()//打表法将1到110之间所有的素数用1标记放入数组中对应位置,其余数用0标记
{
    int i,j;
    for(i=1;i<=110;i++)
        prime[i]=1;
    prime[1]=0;
    for(i=2;i<=110;i++)
    {
        if(prime[i]==1)
        {
            for(j=2*i;j<=110;j+=i)
                prime[j]=0;
        }
    }
}
void dfs (int cur,int n)
{
     if(cur==n+1&&prime[1+a[n]])//如果当前判断的是第n+1个数,则证明前面所有的排序均符合题意,因为是环所以要判断首尾相加是否是素数
     {
         for(int i=1;i<=n;i++)
         printf("%d ",a[i]);
         printf("\n");
         return ;
     }
     else
     {
         for(int i=2;i<=n;i++)//因为题目要求从1开始输出,所以判断时从2开始回溯
          {
              if(!visit[i]&&prime[i+a[cur-1]])//如果i没被用过且他和上一个数的和为素数,则往下执行
              {
                  a[cur]=i;//将i储存开始判断下一个数
                  visit[i]=1;//标记i已经用过
                  dfs(cur+1,n);//继续对下一个数进行判断
                  visit[i]=0;//清除标志
              }
          }
     }
}
int main()
{
    int n,i,j,k=1;
    isprime();
    while(~scanf("%d",&n)&&n)
    {
        memset(a,0,sizeof(a));
        memset(visit,0,sizeof(visit));
        a[1]=1;
        visit[1]=1;
        printf("Case %d:\n",k++);
        if(n==1)//如果n是1则自己成环输出1
            printf("1\n");
        else if(n%2!=0)//如果n为偶数,直接输出No Answer
        {
            printf("No Answer\n");
        }
        else
        dfs(2,n);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值