c++算法之回溯 素数环(二)

来源:互联网 发布:阿里云加速器 编辑:程序博客网 时间:2024/06/06 17:57

Description

输入正整数n,把整数1,2,3,…,n组成一个环,使得相邻两个整数之和均为素数。把全部的解按字典序排序后,从1开始编号,依次输出指定编号的k组解。最后一行输出总的方案数。同一个素数环只算一次。

Input

第1行:2个整数,n(n<=18)和k(1<=k<=10)
第2行:共有k个从小到大排列的整数,表示要输出的解的编号。

Output

前k行,每行一组解,对应于一个输入
第k+1行:一个整数,表示总的方案数。

Sample Input

10 41 2 5 8
Sample Output

1 2 3 4 7 6 5 8 9 101 2 3 4 7 10 9 8 5 61 2 3 8 5 6 7 10 9 41 2 3 10 9 8 5 6 7 496


分析:

算法思维与(一)一样,但需要注意这样两点(坑点):

1.“把全部的解按字典序排序后,从1开始编号,依次输出指定编号的k组解。最后一行输出总的方案数。同一个素数环只算一次。”实现这句话其实就是要固定环的第一个数为1,这样就可以保证不重复,且按字典序排序。

2.要求输出指定的k组解,我是在输出的时候处理的,要统计总数就在那里自增,再判断当前解是否是指定的k组解中的,是才输出

程序实现如下:

#include<cstdio>#include<cmath>int a[19],k,sum,n[11],num=1,q;bool b[19]={0};bool p(int s)//判断是否为素数 {    for(int i=2;i<=sqrt(s);i++)    if(s%i==0) return 0;         return 1;                               }void print(){    sum++;//此时的sum也是此素数环的顺序,产生完所有的素数环之后,sum即为所有的组数     if(sum==n[num])//如果此时是k组数据,才输出     {        for(int i=1;i<q;i++)            printf("%d ",a[i]);        printf("%d\n",a[q]);        num++;//num滚动递增到下一个要求的素数环的序号     }}int search(int r){    for(int i=2;i<=q;i++)        if(!b[i]&&p(i+a[r-1]))//没有被使用过,且与前一个数相加是素数     {        a[r]=i;        b[i]=1;//保存并标记         if(r==q&&p(1+a[q])) print();//如果填完所有的数,且最后一个数与开头的数之和为素数         else search(r+1);//递归回溯         b[i]=0;    }}int main(){    scanf("%d %d",&q,&k);    for(int i=1;i<=k;i++)        scanf("%d",&n[i]);//将k组数据保存在n数组中     a[1]=1;    b[1]=1;//将第一个数固定为1,从2开始搜索     search(2);    printf("%d",sum);//最后输出总数 }