回溯之素数环(7.4.2)

来源:入门经典


生成-测试法:

#include<cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
using namespace std;
#define ll long long
int isp[1000],A[1000];
int is_prime(int x)
{
    int i;
    for(i=2;i<=sqrt(x);i++)
    {
        if(x%i==0) break;
    }
    if(i>sqrt(x))
        return 1;
    else
        return 0;
}
int main()
{
    int n=6;
    for(int i=2;i<=n*2;i++) isp[i]=is_prime(i);//生成素数表,加快后续判断
    for(int i=0;i<n;i++) A[i]=i+1;//第一个排列
    do
    {
        int ok=1;
        for(int i=0;i<n;i++) if(!isp[A[i]+A[(i+1)%n]]) {ok=0;break;}
                                                   //判断合法性
        if(ok)
        {
            for(int i=0;i<n;i++) printf("%d ",A[i]); //输出序列
            printf("\n");
        }
    }while(next_permutation(A+1,A+n)); //1的位置不变//next_permutation()是求下一个排列
    return 0;
}

输出:

当n=12时,用时

 


回溯法:

#include<cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
using namespace std;
#define ll long long
int isp[1000],A[1000];
int vis[1000];
int n;
int is_prime(int x)
{
    int i;
    for(i=2;i<=sqrt(x);i++)
    {
        if(x%i==0) break;
    }
    if(i>sqrt(x))
        return 1;
    else
        return 0;
}
//回溯法
void dfs(int cur)
{
    if(cur==n&&isp[A[0]+A[n-1]]) //递归边界。别忘了测试第一个数和最后一个数
    {
        for(int i=0;i<n;i++) printf("%d ",A[i]);//打印方案
        printf("\n");
    }
    else for(int i=2;i<=n;i++) //尝试放置每个数i
     if(!vis[i]&&isp[i+A[cur-1]]) //如果i没用用过,并且与前一个数之和为素数
    {
        A[cur]=i;
        vis[i]=1; //设置使用标志
        dfs(cur+1);
        vis[i]=0;//清除标志
    }
}
//回溯法比生成-测试法快了好多,即使n=18速度也不错。顺便说一句,把上面的函数名取为dfs并不是巧合--从解答树的角度
//讲,回溯法正是按照深度优先的顺序在遍历解答树
int main()
{
    n=12;
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n*2;i++) isp[i]=is_prime(i);
    A[0]=1;
    dfs(1);
    return 0;
}

而n=12时,用时(快了一些)

而当n=16是两者差别就很大了,虽难都有点慢

猜你喜欢

转载自blog.csdn.net/weixin_42373330/article/details/82561491