Description
问题描述:将从1到n这n个整数围成一个圆环,若其中任意2个相邻的数字相加,结果均为素数,那么这个环就成为素数环。
Input
第一行是测试数据的n(0 <= t <= 12)。
输入数据一定存在解。
Output
输出以1打头所有的素数环,每个解对应一行,每个解元素之间的用空格间隔。
如果存在满足题意叙述的素数环,从小到大输出。
Sample Input
6
Sample Output
1 4 3 2 5 6 1 6 5 2 3 4
tips
基本的回溯问题,通过素数判断进行剪枝
Source
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
bool isPrime_3(int num){
//两个较小数另外处理
if (num == 2 || num == 3)
return true;
//不在6的倍数两侧的一定不是质数
if (num % 6 != 1 && num % 6 != 5)
return false;
int tmp = sqrt(num);
//在6的倍数两侧的也可能不是质数
for (int i = 5; i <= tmp; i += 6)
if (num % i == 0 || num % (i + 2) == 0)
return false;
//排除所有,剩余的是质数
return true;
}
void backtrack(vector<int>&track, vector<bool>& used, vector<int>& num) {
//得出答案
if (track.size() == num.size()) {
int cur = track.back() + track.front();
if (isPrime_3(cur)) {
for (int i = 0; i < track.size(); i++) {
printf("%d ", track[i]);
}
printf("\n");
}
return;
}
for (int i = 0; i < num.size(); i++) {
//排除已经被使用的选项
if (used[i] == true)
continue;
//判断是不是素数,减枝
int cur = track.back() + num[i];
if (!isPrime_3(cur))
continue;
//做出选择
track.push_back(num[i]);
used[i] = true;
//进入下一层选择
backtrack(track, used, num);
//撤销选择
track.pop_back();
used[i] = false;
}
}
int main() {
int n; scanf("%d", &n);
vector<bool>used(n, false);
vector<int>track;
track.push_back(1);
used[0] = true;
vector<int>num(n);
for (int i = 0; i < n; i++)
num[i] = i+1;
backtrack(track, used, num);
/* for (int i = 0; i < num.size(); i++) {
printf("%d ", num[i]);
}*/
return 0;
}