HDU1016 Prime Ring Problem (回溯 + 剪枝)

本文链接: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:\n", 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 }

 

posted @ 2016-04-16 16:32  vrsashly  阅读(229)  评论(0编辑  收藏  举报