题目描述:对于正整数n,对1~n进行排列,使得相邻两个数之和均为素数,输出时从整数1开始,逆时针排列。同一个环应恰好输出一次
n<=16
如输入:6
输出:
1 4 3 2 5 6
1 6 5 2 3 4
思路分析:这道题目第一个整数1已确定,第2个整数可以选择(2~N)间的任意一个数,第3个整数可以在第2个整数选择后余下的N-1个数里任意一个数,后面依此类推,直到选择完N个数。N个数N个选择,我们首先想到用DFS去解决。
第一个数已确定。因此可以从第二个数开始进行选择。DFS(2)选择第二个数,并标记为已选,防止后续重复选择。依次进行DFS(3),DFS(4)…DFS(N)完成N个数的选择。
选择完N个数后,需要设置出口判断条件。该问题需要判断 相邻2个数相加是否素数,如果DFS(N)的时候再进行判断需要再次读取前N个数进行判断,效率非常低。因此我们可以每次调用DFS的时候就进行判断。有如下两种剪枝判断方法:
dfs1: 在每次选取数的时候就进行判断,是否满足与前一个数相加是素数的条件。只选取符合条件的数。
void dfs1(int cur) {
if (cur == N + 1) {
if (IsPrime(gResult[1] + gResult[N])) {
for (int i = 1; i <= N; i++) {
printf("%d", gResult[i]);
}
printf("\n");
}
return;
}
//剪枝在此进行
for (int i = 2; i <= N; i++) {
if (gVi[i] == 0 && IsPrime(gResult[cur-1] + i)) {
gVi[i] = 1;
gResult[cur] = i;
dfs1(cur + 1);
gVi[i] = 0;
}
}
return;
}
dfs2:在dfs入口处进行判断,选数环节只负责选数,不做任何处理。选好数后,在下次的dfs调用中判断前两次的数是否符合条件。
void dfs2(int cur) {
//剪枝在此进行
if (!IsPrime(gResult[cur - 1] + gResult[cur - 2]) && gResult[cur - 1] + gResult[cur - 2]!=1) {
return;
}
if (cur == N + 1) {
if (!IsPrime(gResult[cur - 1] + gResult[1])) {
return;
}
else {
for (int i = 1; i <= N; i++) {
printf("%d ", gResult[i]);
}
printf("\n");
}
}
for (int i = 2; i <= N; i++) {
if (gVi[i] == 0) {
gVi[i] = 1;
gResult[cur] = i;
dfs2(cur + 1);
gVi[i] = 0;
}
}
return;
}
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define MAX_N 21
int N;
int gResult[MAX_N];
int gVi[MAX_N];
bool IsPrime(int num) {
if (num < 2) return false;
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) return false;
}
return true;
}
void dfs1(int cur) {
if (cur == N + 1) {
if (IsPrime(gResult[1] + gResult[N])) {
for (int i = 1; i <= N; i++) {
printf("%d", gResult[i]);
}
printf("\n");
}
return;
}
//剪枝在此进行
for (int i = 2; i <= N; i++) {
if (gVi[i] == 0 && IsPrime(gResult[cur-1] + i)) {
gVi[i] = 1;
gResult[cur] = i;
dfs1(cur + 1);
gVi[i] = 0;
}
}
return;
}
void dfs2(int cur) {
//剪枝在此进行
if (!IsPrime(gResult[cur - 1] + gResult[cur - 2]) && gResult[cur - 1] + gResult[cur - 2]!=1) {
return;
}
if (cur == N + 1) {
if (!IsPrime(gResult[cur - 1] + gResult[1])) {
return;
}
else {
for (int i = 1; i <= N; i++) {
printf("%d ", gResult[i]);
}
printf("\n");
}
}
for (int i = 2; i <= N; i++) {
if (gVi[i] == 0) {
gVi[i] = 1;
gResult[cur] = i;
dfs2(cur + 1);
gVi[i] = 0;
}
}
return;
}
int main() {
int T, test_case;
freopen("1.txt", "r", stdin);
setbuf(stdout, NULL);
scanf("%d", &T);
for (test_case = 1; test_case <= T; test_case++) {
scanf("%d", &N);
printf("#%d:\n", test_case);
if (N == 1) {
printf("%d\n", 1);
}
else {
gResult[1] = 1;
gVi[1] = 1;
dfs2(2);
}
}
return 0;
}
输入:
2
6
8
输出:
#1:
1 4 3 2 5 6
1 6 5 2 3 4
#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