素数环 题解

素数环:从1 到n这n 个数摆成一个环,要求相邻的两个数的和是一个
素数。

给定n的取值,输出其解所有的排列方式及解的个数

样例输入

6

样例输出

<1>1 4 3 2 5 6

<2>1 6 5 2 3 4

2

注:此题素数环拥有多种输入输出格式,小编只是举例说明。此程序只支持,输入填入数的范围,输出素数环所有解的排列及排列数量。不为某谷……等网站题目的输出格式,但思路相同,解相同,还麻烦大家自行修改输出格式。

今天为大家带来一道经典深搜题--------素数环。读完题后即可得到一种思路:利用深搜递归的特性,一个一个像填表一样将满足条件的合法数依次填入环,再定义一个判断素数的函数来判断相邻两个数和是否为素数,计入一个一维数组中,在定义一个计数器tot记录解的个数,同时也可于每次输出表示此时输出的是第几组解。此时,必须注意一个题目的要求:从1 到n这n 个数摆成一个环,即为每个数只可用一次,故可定义一大小为n的bool一维数组数组来记录,判定在同一素数环中是否有两个重复的数,即可完美的满足题意。

大体思路确定了,俗话说细节决定成败,写代码也是一样。那么在代码细节上我们应该注意些什么呢?在此,小编在写代码时遇到了几个细节问题:

1.与search函数,即深搜dfs函数中,在判定其相邻两点和是否为素数时,不要忘记判定此点是否被用过。

2.在素数环填完后,不要忘记素数环是一个环,要将也相邻的两数a[n]与a[1]的和也判断素数,在判定此素数环是否合法后再进行输出。

3.由于素数环是从1开始求解,故在dfs搜索时,必会使用其前驱(即上一个节点)a[0]的值,但a[0]的值永远不变,为初始值0,故会出现大错(可能会1分不得)。故不可直接从a[1]开始搜索,需用循环先枚举a[1]的取值,从下标为2开始搜索。(重中之重,核心问题所在)

讲了着么多,上AC代码:

#include<iostream>
using namespace std;
bool b[101]={0};//b数组记录与同一个环中是否用了重复的数
int tot=0,a[101]={0},n;//tot记录此时搜索到第几个解,并统计解的个数,a数组保存素数环的排列,每次搜索成功一种解就输出
int print()//输出素数环每个解的排列方式
{
int j;
tot++;//进入print函数即代表搜索到了一组解,即可将计数器tot++
cout<<"<"<<tot<<">";//输出即表示,此时输出的是第tot组解
for(j=1;j<=n;j++)
{
cout<<a[j]<<" ";
}//输出素数环的排列,即一组解
cout<<endl;
}
bool pd(int a,int b)//判断相邻两数的和是否为素数,传参两个数
{
int i;
int c=a+b;//记录两个数的和
if(c==0||c==1)
{
return false;
}//如和为0或1,即0,1均不为素数,故返回false,表示此搜索情况构不成素数环

//tips:其实此判断可有可无,因解其最小值,1加上一个比一大的数定大于0和1
for(i=2;i<c;i++)
{
if(c%i==0)
{
return false;
}
}//从2搜索到c-1,因素数的定义为除1与本身外并无其他因数,故在2~c-1的区间内只要有一数可整除,便不是素数,故返回false,表示此搜索情况构不成素数环
return true;//如直至循环结束都无返回值,即表示于2~c-1的区间内无c的因数,即c为素数,即两数和为素数,故返回true,表示此搜索情况可以构成素数环
int search(int t)//深搜,函数名也可写为dfs,从a[t]开始搜索,建立素数环
{
int i;
for(i=1;i<=n;i++)//从1~边界n,区间内遍历,寻找和为素数的两数
{
if(pd(a[t-1],i)&&(!b[i]))//找到一个可与a[t-1],即前一个数两两匹配的数a[t],条件为两数之和为素数(故调用pd,即判断素数函数),且于此素数环中没用过此数(利用bool类型的b数组记录此数是否用过,没用过即为0,用过记为1)
{
a[t]=i;//如满足上述条件,即此数i可填入单元a[t]之中,即是一种解,将其计入a数组
b[i]=1;//将计入单元a[t]的数字i的标记即为1,即在此素数环中已用过此数
if(t==n)//如记录的t下标已到了最终边界n,即已填完此素数环
{
if(pd(a[n],a[1])==true)//因此素数环是一个环,是联通的,故a[n]与a[1]亦相邻,故需判断a[n]与a[1]的和是否为素数(调用判断素数函数pd),如返回值为true,则此素数环为正解,为合法的素数环,如返回值为false,即此素数环不合法,为错误解
{
print();//如是,调用输出函数print(),将正解a数组输出
}
}
else
{
search(t+1); //如不是,即没有填完,则继续填写下一个数字单元a[t+1]
}
b[i]=0; //回溯
}
}
}
int main()
{
int i;
while(cin>>n)//小编将这里写成了可输入多组测试数据,大家可尽情调试哈
{
for(i=1;i<=n;i++)//由于素数环是从1开始求解,故在dfs搜索时,必会使用其前驱(即上一个节点)a[0]的值,但a[0]的值永远不变,为初始值0,故会出现大错(可能会1分不得)。故不可直接从a[1]开始搜索,需用循环先枚举a[1]的取值,从下标为2开始搜索。
{
a[1]=i;//枚举a[1]的值,并复值成功
b[i]=1;//将填入a[1]的数标记为1,即表示在此素数环中已用过此数

search(2);//从下标为2开始搜索
}
cout<<tot<<endl;//遍历完 a[1]的值,即代表所有的素数环可能都已被遍历,即可输出tot的值,即输出解的个数
}
return 0;//完美结束
}

posted on 2020-08-04 21:59  田宸玮  阅读(859)  评论(0编辑  收藏  举报

导航