原题链接: UVa-524
题目大意:
模输入正整数n,把整数1,2,3...,n,组成一个环,使得相邻的两个整数之和均为素数,输出从整数1开始逆时针排序。同一个环应恰好输出一次.n<=16。
解题思路:
如果这道题是在紫书上看到的,那这道题应该也没什么问题(估计也不会看到我这篇博客)。因为这道题的整体框架和书上前面的引例——八皇后问题的回溯法解法大同小异。都是通过递归来枚举,并判断是否符合题意(环上前后两项之和为素数),当递归到解答树的叶子节点的时候进行输出。
需要注意输出格式,另外还有一个小技巧,在判断是否已经放入环中的时候可以直接使用一个数组vis[i]来判断i是否在环中,在递归函数之后,需要记得将vis[i]恢复。不然会出错。
另外,既然是环,如果使用是回溯法的框架的话,最后输出之前记得判断第1个和第n个之和是否为素数。
看到OJ上排名前几的一个代码,直接把素数给列出来了,第一眼看上去:还有这操作?裁判他耍赖皮啊。仔细想想确实节约不少时间。。。
代码
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
bool is_prime(int n);
void solve(int cur);
const int MAXN = 16 + 4;
int order[MAXN], vis[MAXN];//order:用来存储序列,记录第i个位置的数值;vis来记录i是否在已经在order中
int n;
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int kase = 0;
while (cin >> n) {
if (kase++) cout << endl;
cout << "Case " << kase << ":\n";
memset(vis, 0, sizeof(vis)); //每一轮都要初始化vis
order[1] = 1;
solve(2);
}
return 0;
}
void solve(int cur)
{
if (cur == n+1 && is_prime(order[1]+order[n])) { //输出之前要判断 order[1]+order[n]是否为质数
for (int i = 1; i <= n; i++) {
if (i != 1) cout << " ";
cout << order[i];
}
cout << endl;
}
else {
for (int i = 2; i <= n; i++) {
if (!vis[i] && is_prime(order[cur-1]+i)) { //既符合条件,又不在环中
vis[i] = 1;
order[cur] = i;
solve(cur+1);
vis[i] = 0; //要恢复全局变量
}
}
}
}
bool is_prime(int n) //判断是否为素数(伪)
{
for (int i = 2; i <= sqrt(n)+1; i++)
if (n%i == 0) return false;
return true;
}