素数环(深搜 C++版)

素数环
总时间限制: 1000ms 内存限制: 65536kB
描述
输入正整数n,把整数1,2,3,…,n组成一个环,使得相邻两个整数之和均为素数。小强同学看过这个题,笑了:呵呵,打表!
Mr. Wu为了阻止小强打表,决定这样:
把全部的解按字典序排序后,从1开始编号,依次输出指定编号的k组解。最后一行输出总的方案数。同一个素数环只算一次。
输入
第1行:2个整数,n(n<=18)和k(1<=k<=10)
第2行:共有k个从小到大排列的整数,表示要输出的解的编号。
输出
前k行,每行一组解,对应于一个输入
第k+1行:一个整数,表示总的方案数。
样例输入

10 4
1 2 5 8

样例输出

1 2 3 4 7 6 5 8 9 10
1 2 3 4 7 10 9 8 5 6
1 2 3 8 5 6 7 10 9 4
1 2 3 10 9 8 5 6 7 4
96

提示
输入样例说明:
对1,2,…,10组成素数环。要输出字典序的第1,2,5,8等4组解
输出样例说明:
第1,2,5,8组解分别是样例中所列的4行。总共有96组解。

思路点拔:典型深搜,先写一个判断质数的函数,搜索是,判断没相邻两个数的和是否为素数,由于本题是一个环,所以再判断一下

#include<cstdio>
#include<cmath>
int b[23],ans,m,n,tot,c[23],a[23]={0,1},t=1;
bool zs(int x,int y) //判断质数
{
    int ans=x+y;
    for(int i=2;i<=sqrt(ans);i++)
    {
        if(ans%i==0)
            return 0;
    }
    return 1;
}
void print() //输出函数
{
    for(int i=1;i<m;i++)
        printf("%d ",a[i]);
    printf("%d\n",a[m]);
}
void dfs(int k) //搜索
{
    for(int i=2;i<=m;i++) 
    {
        if(zs(a[k-1],i)==1&&b[i]==0) //判断相邻两个数的和是否为质数,并且没有用过
        {
            b[i]=1;
            a[k]=i;
            if(k==m&&zs(a[k],a[1])==1) 
            //如果填满了,再判断一下最后一个数与第一个数的和是否为素数
            {
                tot++;//如果是,总方案数加1
                if(tot==c[t]) //如果是我们想要的那组数据
                {
                    t++;
                    print();    //输出
                }
            }
            else dfs(k+1); //继续搜索填充下一个数
            b[i]=0;//回溯
        }
    }
}
int main()
{
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&c[i]);
    dfs(2);//搜索
    printf("%d\n",tot);输出总方案数
    return 0;
}

细心的读者会发现,上面的代码看上去万无一失,但会超时,因为在dfs中反
复的调用zs函数,时间复杂度会很高,所以关于质数,需要用另外一种方
式处理——由于本题中n小于等于18,所以所有数都不可能大于35,所以
用一个数组,若这个元素的下标为素数,如a[2],a[3],a[7]等就赋为1,否则
就赋为0,注意:本题必须用格式输入输出,因为这个方法是本题唯一的
正解,它的运行时间本来就临近超时,(700<=t<1000),如果用流输入
输出,同样会超时,废话不多说,上代码!

#include<cstdio>
#include<cmath>
int b[23],ans,m,n,tot,c[23],a[23]={0,1},t=1;
int zs[35]={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};
void print() //输出函数
{
    for(int i=1;i<m;i++)
        printf("%d ",a[i]);
    printf("%d\n",a[m]);
}
void dfs(int k) //搜索
{
    for(int i=2;i<=m;i++) 
    {
        if(zs[a[k-1]+i]==1&&b[i]==0) //判断相邻两个数的和是否为质数,并且没有用过
        {
            b[i]=1;
            a[k]=i;
            if(k==m&&zs[a[k]+a[1]]==1) 
            //如果填满了,再判断一下最后一个数与第一个数的和是否为素数
            {
                tot++;//如果是,总方案数加1
                if(tot==c[t]) //如果是我们想要的那组数据
                {
                    t++;
                    print();    //输出
                }
            }
            else dfs(k+1); //继续搜索填充下一个数
            b[i]=0;//回溯
        }
    }
}
int main()
{
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&c[i]);
    dfs(2);//搜索
    printf("%d\n",tot);输出总方案数
    return 0;
}

思路很简单,但有很多坑,需要多加注意哦~

猜你喜欢

转载自blog.csdn.net/qq_42995099/article/details/81812971