本文链接:http://www.cnblogs.com/Ash-ly/p/5398684.html
题意:
给你一个数字N(N <= 20),要求你把这N个数组成一个环,环内的数字不能重复,左右相邻的两个的和是素数。给出最后的答案。
思路:
利用回溯剪枝算法,N个数,每个数有N种状态,枚举这N个状态,枚举过程中剪枝优化。
代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cstring> 5 #include <cmath> 6 #include <cstdlib> 7 #include <algorithm> 8 using namespace std; 9 10 const int MAXN = 43; 11 int n; 12 //素数表 13 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}; 14 //判断是否重复 15 int used[MAXN]; 16 17 //素数环 18 int circle[MAXN]; 19 20 //判断 第 key 个位置的数字是否合法 21 int check(int key) 22 { 23 if( used[ circle[key] ] ) //之前被用过 24 return 0; 25 if(!isprime[ circle[key] + circle[key - 1] ])//和前面一个组成了非素数 26 return 0; 27 if(key == n && !isprime[ circle[key] + 1 ])//最后一个数和第一个数的和也不能是素数 28 return 0; 29 return 1; 30 } 31 32 void backtrack(int key) 33 { 34 if(key > n)//回溯完毕 打印结果 35 { 36 for(int i = 1; i <= n; i++) 37 cout <<(i == 1? "" : " ") << circle[i]; 38 cout <<endl; 39 } 40 else 41 { 42 for(int i = 2; i <= n; i++) //这个位置一共有 n - 1 个状态,分别枚举 43 { 44 circle[key] = i; 45 if( check( key ) ) //剪枝处理 46 { 47 used[i] = 1; //标记这个点已被用 48 backtrack(key + 1); 49 used[i] = 0; //恢复现场 50 } 51 } 52 } 53 } 54 55 int main() 56 { 57 int kas = 1; 58 while(cin >> n) 59 { 60 printf("Case %d: ", kas++); 61 memset(used, 0, sizeof(used)); 62 memset(circle, 0, sizeof(circle)); 63 circle[1] = 1; //第一个数字从 1 开始 64 backtrack(2); //从第二个数字开始求解 65 cout << endl; 66 } 67 return 0; 68 }