1.理解什么是素数,只能被1和它本身整除的数叫素数。
bool isPrime(int m) //求m是不是素数
{
for ( int i = 2;i<=(int)sqrt(m);i++)
{
if(m % i==0 ) return false;
}
return true;
}
2.DFS深度优先搜索。【比如我们要求n = 4个的素数环。】
1是必选项,然后开始遍历其他。根据要求,它是按照字典序来排序,所以应该找 没有选择过的,且最小的数 。即从头开始遍历,找与前一项的和是素数。当最后一项(4个素数换即第4项时),如果条件符合还要看第4个数是不是与第1个数(即1)的和是素数,如果与要求正确。
①。首先是找的2,与前一项相加。2+1 =3,是素数,满足要求、
②。然后找的3,3+2 = 5是素数。满足要求。
③。然后找的4,4+3 = 7是素数,这是第一个条件。同时4=n,是最后一项,还要对与第1项(即1)的和判断是否为素数,这是第二个条件。如果这两个条件都满足才是一个完整的素数环。
4+3 = 7,是素数,4+1 = 5是素数。因此,1,2,3,4是一个素数环。
3.跟着代码走一遍:
1.创建数组 str[22],vis[22]。其中str数组用来存放保存好的路径信息,vis数组用来表示是否访问过第 i 个点。
创建数组n用来表示有n个元素的素数环。
int str[22];
int vis[22];
int n;
2.主函数走起来,先对str数组和vis数组初始化,然后输入n:
int main(){
//Initialize:
for(int i = 2;i<=n;i++)
{
str[i] = 0;
vis[i] = 0; //vis=0表示没有被访问过
}
str[1] = 1; //第一步必须走1,根据题目要求,环必须从1开始
vis[1] = 1; //既然第一步走过了,纳闷他必然访问过了。
}
3同时我们发现找下一步是个深搜递归的过程,如果可以找到就一直往下找,如果找到全部就输出结果,否则返回上一步,直到所有可能的结果都走遍。
void dfs(int step){ //表示我已经走了step步了
//1.如果已经走了n步了,那么就要判断第n位(str[n])与1位(1)的和是否为素数,如果是那么就输出整个结果
if(step == n){
if(isPrime(str[n] + 1)){
for(int i=1;i<=n;i++){
printf("%d%c",str[i],(i<n)?' ':'\n');
}
}
return;
}
//2剩下的情况就是还没走完,我们就要继续走下去,从小到大遍历所有的点,如果满足 该点没访问过 且 该点与保存好的数组str的最后一项的和是素数,那么久保存这个点,并访问下一个节点。
for(int i=2;i<=n;i++){
if(!vis[i] && isPrime(i+str[n]){
str[n+1] = i; //保存这个点
vis[n+1] = 1; //标记这个点已经被访问过
dfs(n+1); //已经走了n+1步,进入找下一个点的过程中。
vis[n+1] = 0; //这一步大家可能不太容易理解。比如第2步走完了,发现后面的点都行不通,则要返回上一步继续走,这时候就要把vis数组重新置为0,保证后面可以再次访问到该点
}
}
5.所以刚才的主函数中只要再添加一行就可以啦,即
dfs(1); //表示已经访问了1个节点。即节点1.
完整代码如下:(HDU1016素数环)
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int n;
int str[22];
int vis[22];
bool isPrime(int m){
for(int i=2;i<=(int)sqrt(m);i++){
if(m%i==0)return false;
}
return true;
}
void dfs(int step){ //表示已经走了step步后怎么走
if(step == n && isPrime(str[n]+1)){
for(int i=1;i<=n;i++){
printf("%d%c",str[i],(i<n)?' ':'\n');
}
return; //后面的语句就不用访问了
}
for(int i=2;i<=n;i++){
if(!vis[i] && isPrime(i+str[step])){
str[step+1] = i;
vis[i] = 1;
dfs(step+1);
vis[i] = 0;
}
}
}
int main(){
int kase = 0;
while(cin >> n){
for(int i=2;i<=n;i++){
str[i] = 0;
vis[i] = 0;
}
str[1] = 1;
vis[1] = 1;
cout << "Case " << ++kase << ":"<< endl;
dfs(1);
cout << endl;
}
}
6.总结:做了n次才做出来,费了很长时间。希望不要操之过急,稳扎稳打。
7.补充:我第一次Presentation Error了,原因是我写的是前几个case都有空格,最后一个没有。他的格式有些不一样,是每一行都要有一个空格。不要在意细节,主要看懂思想和方法。