问题描述
素数环:从1到n这n个数摆成一个环,要求相邻的两个数的和是一个素数。如,n=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
其总数为4
输入
n的值(n不大于15)
输出
打印素数环并输出数量,如果不存在素数环则输出 “no solution!”(不输出双引号)。
解法:回溯
思路
(1)此题目的解法类似于全排列,用1-20的数字放在当前位置来进行试探
(2)判断的条件为:当正在填写中间的位置时,只用判断当前填写的数字+上一个填写的数字是不是为素数,当在填写最后一个位置时,不仅要判断上一个数字的和,还要判断与第一个位置数的和是否为素数
(3)如果当前位置不符合条件,则回退,将arr[i]重新置为0
特殊情况
最后一个数字和第一个数字也是相邻的两个数
代码
import java.util.Scanner;
/**
* 素数环:把从1到n这n个数摆成一个环,要求相邻的两个数的和是一个素数。
* @author Administrator
*
*/
public class PrimeLoop {
static int[] arr;
static int n;
/* 标记是否找到环 */
static boolean flag = false;
/* 环的个数 */
static int count = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
arr = new int[n];
// 默认环的第一个数为1
arr[0] = 1;
solve(1);
System.out.println(flag ? count : "no solution!");
}
private static void solve(int i) {
if(i == n){
flag = true;
++count;
// 遍历输出
for (int j = 0; j < n; j++) {
System.out.print(arr[j] + " ");
}
System.out.println();
}else {
// 在第i个位置上用2-n的数字来挨个试探
for (int j = 2; j <= n; j++) {
if(!conclude(j, i)){
arr[i] = j;
if(judge(i)){
// 当前j符合条件继续填写下一个试探的数字
solve(i + 1);
arr[i] = 0;
}
}
}
}
}
/* 判断j是否在前n个数字里面被使用过 */
private static boolean conclude(int j, int n) {
for (int i = 0; i < n; i++) {
if(j == arr[i]){
return true;
}
}
return false;
}
/* 判断已经放置的前i个数字是否符合相邻两个数字和是素数的条件 */
private static boolean judge(int i) {
if(i == 0) return true;
if(i == n - 1){
return isPrime(arr[0] + arr[n - 1]) && isPrime(arr[i] + arr[i - 1]);
}
return isPrime(arr[i] + arr[i - 1]);
}
/* 判断素数 */
private static boolean isPrime(int n) {
for (int i = 2; i <= Math.sqrt(n); i++) {
if(n % i == 0){
return false;
}
}
return true;
}
}