问题描述
原文的全英的,这里就不放了,说一下大概就好了。
原文大意:输入一个正整数n(0<n<20),将1~n这n个数排成一个圆环,在这个圆环中,任意两个相邻的数的和为素数,故称素数环,如下图:
输入规范
有多组输入,每次输入一个n(0<n<20)
输出规范
输出入示例所示,要注意的是就算没有结果也要打印一个空行
输入示例
6
8
输出示例
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
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
============================================================
写在题解前:
这道题本质是深度优先搜索,如果不考虑时间复杂度的话这道题其实并不难,这道题让我觉得值得记录的地方有两个:
1、使用素数表,很大程度上减少了判断俩个数的和是否是素数所花费的时间
2、合理剪枝(第19行-第22行代码),优化搜索
不过可能是因为java跑得本来就比C/C++慢吧,用java写出来的代码跑的时间将近是C/C++的十倍,结果超时。
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int[] prime={0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0};
static int[] vis,s;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = 0;
while(true){
int n = sc.nextInt();
t++;
vis = new int[n+1];
s = new int[n];
s[0] = 1;
System.out.println("Case "+t+":");
if(n%2==0) // 奇数不可能成立
dfs(1,n);
else if(n==1) // 1是特殊情况
System.out.println("1");
System.out.println();
}
}
private static void dfs(int a,int n) {
if(a==n){
if(prime[s[0]+s[a-1]]==1){
for(int i=0;i<n-1;i++){
System.out.print(s[i]+" ");
}
System.out.println(s[n-1]); // 最后一个数后面不用留空格
}
} else {
for(int i=2;i<=n;i++){
if(vis[i]!=1&&prime[s[a-1]+i]==1){ // 当前数没有被访问过且与上一个数的和为素数
vis[i] = 1;
s[a] = i;
dfs(a+1,n);
vis[i] = 0; // 回溯
}
}
}
}
}