素数环(回溯+搜索)

【问题描述】

给定一个数n,求1..n组成的环,使得环上相邻的元素和为素数。

【输入格式】

输入一个正整数n(1≤n≤17)

【输出格式】

把1放在第一位置,按照字典顺序不重复的输出所有解(顺时针,逆时针算不同的两种),相邻两数之间严格用一个空格隔开。

如果没有答案请输出no answer

【输入样例】

8

【输出样例】

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

思路:

非常经典的一道DFS(剪枝)题目,我也是非常快就做出来了。我的思路就是用一个DFS函数,函数里“随便”写点东西,然后定义一个ans数组用于存储最终的答案序列,定义一个vis数组用于检查这个数是否已经被用过了,定义一个isPrime函数,用于判断是不是质数,然后就是要注意以下4个易错点:

1.注意到第一个数固定为1了,所以DFS函数里的递归下标要从2开始,ans[1]要固定为1,vis[1]要为1(表示1已经用过了),调用函数时用DFS(2)。(我这个的下标是从1开始的,如果你们想从0开始,就把上面几个改一改,每个-1就好了)

2.小于2的数不是质数;2也是质数(因为判断质数有人可能会写成return n>2,把=漏掉,就不对了)

3.如果无解要输出no answer,所以可定义一个cnt,每次查询到一个解cnt++,最后判断cnt是否为0(读者:这要你教吗?!

4.注意是组成一个环,不是排成一横排!!!所以DFS函数最后面要判断一下第一个元素(其实就是1)和最后一个元素的和是否为质数,是的话再输出,同时cnt++。

AC代码:

温馨提示:这个注释有点多,主要是想让你们看懂我的思路,如果要复制的话,建议把注释删一点,特别是第一行,因为......

//2024/7/17刷题记

#include <bits/stdc++.h>//我是下标从1开始的,如果不习惯,自己理解一下,不要一会儿1一会儿0

using namespace std;

int cnt=0;//用于判断是否有解

int n;//全局变量

int ans[20];//最终的答案序列

bool vis[20];//用于检查这个数是否被用过,最好用bool,因为有些题目会卡你的内存

bool isPrime(int n)//判断质数

{

    for(int i=2;i<=n/i;i++)

    {

        if(n%i==0)

        {

            return false;

        }

    }

    return n>=2;//要注意不是return true

}

void DFS(int deep)//递归函数

{

    if(deep==n+1)//如果所有数都用完了

    {

        if(isPrime(ans[1]+ans[n]))//注意是一个环,所以第一个和最后一个相加也要是质数

        {

            cnt++;

            for(int i=1;i<=n;i++)

            {

                cout<<ans[i]<<" ";

            }

            cout<<endl;//别忘了换行

        }

        return;//注意这个return不要用错位置,无论满不满足条件都要结束,否则会越界或爆掉

    }

    for(int i=2;i<=n;i++)//第一个确定是1了,所以从2开始

    {

        if(!vis[i]&&isPrime(i+ans[deep-1]))//选中的这个数一定要还没被访问过

        {

            vis[i]=1;

            ans[deep]=i;

            DFS(deep+1);//别忘了+1

            vis[i]=0;//回溯取消标记

        }

    }

}

int main()

{

    cin >> n;

    ans[1]=1;//注意第一个数固定为1

    vis[1]=1;//1已经用过了,不标记会导致后面还会用到这个1

    DFS(2);//注意从2开始,因为第一个数不用再判断了,已经固定为1了

    if(!cnt)

    {

        cout<<"no answer";//一定不要忘记这个

    }

    return 0;

}

 今天的博客就到这里了,(套句子)作者创作不易,请勿抄袭,转载请标明出处,谢谢!当然,如果觉得代码还行的话,建议点个关注点个赞,顺便收藏一下,谢谢!【笔芯】

当然,也鼓励大家评论,可以指出作者的不足,我看到后(我每天都会看一看的)会回复,也会努力改正。

最后的最后,给大家整个活吧:本博客共个1669字,不信可自测。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值