【问题描述】
给定一个数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字,不信可自测。