上次使用递归完成了素数环问题,优化也做的还可以。主要思想是变量next,fath。递归开始的时候,next作为将要填入数字的位置,将fath保存到素数环中,然后访问此结点。判断将要填入的位置是否是n,为n表示素数环将要填满,首尾相接成功的话,打印素数环,return。而核心部分,就是
For i : 1~n {
符合条件则:
DFS(next+1, i) // i 作为局部变量存入栈内存
vis[i] = 0
//回溯
}
主函数只需要DFS(1, 1)即可。
现在学习一种新的方法,它的DFS只使用了1个参数cur
代码如下:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int a[20] = {1}, su[40];
int n;
bool vis[20]; //bool类型的vis可以节省一点内存
void dfs(int cur){
if(cur == n&&su[1+a[n-1]]){ //cur==n表示素数环将要填满
int i;
for(i = 0; i < n-1; i++)
printf("%d ", a[i]);
printf("%d\n", a[i]);
} //要么打印可行解,要么DFS
else
for(int i = 2; i <= n; i++){
if(!vis[i] && su[i+a[cur-1]]){
a[cur] = i;//可行,存入素数环
vis[i] = 1;
dfs(cur+1);//递归下一个环
vis[i] = 0;//回溯
}
}
}
int main(){
int cas = 0;
su[2] = su[3] = su[5] = su[7] = su[11] = su[13] = su[17] = su[19] = 1;
su[23] = su[29] = su[31] = su[37] = 1;//依旧使用打表的方法避免无谓的DFS
while(scanf("%d", &n) != EOF){
printf("Case %d:\n", ++cas);
if(su[n]&&n != 2){
puts("");continue;
}
else if(n == 1||n == 9||n == 15){
puts("");continue;
}
memset(vis, 0, sizeof(vis));
dfs(1);
puts("");
}
}
核心思想:
For i : 2~n{
符合条件则
a[cur] = i
vis[i]
DFS(cur+1)
vis[i] X
}
并没有把结点存入栈内存的局部变量,符合条件就直接存入素数环,做访问标记,思路更直接清晰。