题意:
给你一个数字N(N <= 20),要求你把这N个数组成一个环,环内的数字不能重复,左右相邻的两个的和是素数。给出最后的答案。
思路:
利用回溯剪枝算法,N个数,每个数有N种状态,枚举这N个状态,枚举过程中剪枝优化。
代码:
#include <cstdio> #include <iostream> #include <cstring> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; const int MAXN = 43; int n; //素数表 int isprime[MAXN] = {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, 1, 0}; //判断是否重复 int used[MAXN]; //素数环 int circle[MAXN]; //判断 第 key 个位置的数字是否合法 int check(int key) { if( used[ circle[key] ] ) //之前被用过 return 0; if(!isprime[ circle[key] + circle[key - 1] ])//和前面一个组成了非素数 return 0; if(key == n && !isprime[ circle[key] + 1 ])//最后一个数和第一个数的和也不能是素数 return 0; return 1; } void backtrack(int key) { if(key > n)//回溯完毕 打印结果 { for(int i = 1; i <= n; i++) cout <<(i == 1? "" : " ") << circle[i]; cout <<endl; } else { for(int i = 2; i <= n; i++) //这个位置一共有 n - 1 个状态,分别枚举 { circle[key] = i; if( check( key ) ) //剪枝处理 { used[i] = 1; //标记这个点已被用 backtrack(key + 1); used[i] = 0; //恢复现场 } } } } int main() { int kas = 1; while(cin >> n) { printf("Case %d:\n", kas++); memset(used, 0, sizeof(used)); memset(circle, 0, sizeof(circle)); circle[1] = 1; //第一个数字从 1 开始 backtrack(2); //从第二个数字开始求解 cout << endl; } return 0; }
时间: 2024-11-10 11:10:37