hdu 1016 Prime Ring Problem

Prime Ring Problem

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 40640    Accepted Submission(s): 17951

Problem Description
A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.
Note: the number of first circle should always be 1.
 
Input
n (0 < n < 20).
 
Output
The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.
You are to write a program that completes above process.
Print a blank line after each case.
 
Sample Input
6 8
 
Sample Output
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
 
回溯法:
题意:输入一个 n 找出1~n的组合,使得相邻两个数之和为素数;
分析:预处理40之间的素数,然后回溯;
 1 #include<iostream>
 2 #define N 25
 3 #define M 40
 4 using namespace std;
 5 
 6 bool is_prime[M],visited[N];
 7 int n,test,ans[N];
 8 
 9 void work(int k)
10 {
11     int i;
12     if(k==n+1)
13     {
14         if(!is_prime[ans[n]+ans[1]]) return ;
15         for(i=1;i<=n-1;i++)
16             cout<<ans[i]<<" ";
17         cout<<ans[i]<<endl;
18         return ;
19     }
20     for(i=2;i<=n;i++)
21     {
22         if(!visited[i]&&is_prime[ans[k-1]+i])
23         {
24             visited[i]=true;
25             ans[k]=i;
26             work(k+1);
27             visited[i]=false;
28         }
29     }
30 }
31 
32 bool prime(int n)
33 {
34     if(n==1) return false;
35     if(n==2||n==3) return true;
36     int i;
37     for(i=2;i<n;i++)
38         if(n%i==0)
39             return false;
40     return true;
41 }
42 
43 int main()
44 {
45     int i;test=1;
46     for(i=1;i<M;i++) is_prime[i]=prime(i);
47     while(cin>>n)
48     {
49         ans[1]=1;
50         memset(visited,false,sizeof(visited));
51         cout<<"Case "<<test<<":"<<endl;
52         work(2);
53         test++;
54         cout<<endl;
55     }
56     return 0;
57 }
View Code

大意是给出N,求所有由1-N组成的首位为1环形序列,要求相邻两数的和为素数。素数判断不说了,因为N小于20,所以可以预先将素数打表保存供后面查询。因为规定了首位为1,所以从1开始搜索所有的可能,用visit[]标记访问过的数字,每次搜到深度等于N的时候就可以打印结果path[]了。没有结果的也就空着输出就好了,格式方面注意每行结果的最后一个数字后面没有空格。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <math.h>
 5 #define MAX 51
 6  
 7 int n;
 8 int path[MAX];
 9 int visit[MAX];
10 int prime[MAX];
11  
12 int isPrime(int x)
13 {
14     int i;
15     for (i = 2; i <= sqrt(x*1.0); i++)
16     {
17         if (x % i == 0) return 0;
18     }
19     return 1;
20 }
21  
22 void dfs(int x)
23 {
24     int i;
25     if ((x == n) && prime[path[1] + path[n]])
26     {
27         for (i = 1; i < n; i++)
28         {
29             printf("%d ", path[i]);
30         }
31         printf("%d
", path[n]);
32         return;
33     }
34     else
35     {
36         for (i = 2; i <= n; i++)
37         {
38             if (!visit[i] && prime[path[x] + i])
39             {
40                 path[x+1] = i;
41                 visit[i] = 1;
42                 dfs(x+1);
43                 visit[i] = 0;
44             }
45         }
46     }
47 }
48  
49 int main()
50 {
51     int i, t;
52  
53     // 打表 
54     for (i = 1; i < MAX; i++)
55     {
56         if (isPrime(i)) prime[i] = 1;
57         else prime[i] = 0;
58     }
59  
60     // 输出 
61     t = 0;
62     while(scanf("%d", &n) != EOF)
63     {
64         printf("Case %d:
", ++t);
65         memset(visit, 0, sizeof(visit));
66         path[1] = 1;
67         visit[1] = 1;
68         dfs(1);
69         printf("
");
70     }
71     //system("pause");
72     return 0;
73 }
View Code
分析:
(1)这道题非常类似于N皇后问题,使用的是深度优先搜索方法
(2)虽然说打印要求是按照顺时针和逆时针顺序打印,其实按照从小到大的搜索顺序搜索后的结果就是符合输出顺序的。
(3)由于是20以内的数字,所以判断质数的方法是直接打表后一个简单的循环判断一下是否为质数
(4)程序中mark数组是为了标记某个数字是否使用过了,num数组存储的是数字链表的存储顺序。
 1 #include <stdio.h>
 2 
 3 int num[21],mark[21],n;
 4 int prime_num[12] = {2,3,5,7,11,13,17,19,23,29,31,37};
 5 
 6 //判断是否是质数,是返回1,不是返回0
 7 int is_prime(int a)
 8 {
 9     for(int i = 0; i < 12;i++)
10     if(a==prime_num[i])return 1;
11     return 0;
12 }
13 void print_num()
14 {
15     for(int i = 1; i < n;i++)
16     printf("%d ",num[i]);
17     printf("%d",num[n]);
18 }
19 
20 int dfs(int pre,int post,int flag)
21 {
22     //如果不符合,直接返回
23     if(!is_prime(pre+post))
24     return 0;
25     num[flag] = post;
26     if(flag==n&&is_prime(post+1))
27     {
28         print_num();
29         printf("
");
30         return 1;
31     }
32     //使用过了这个数字就标记为0
33     mark[post] = 0;
34     for(int i = 2;i<=n;i++)
35     if(mark[i]!=0 && dfs(post,i,flag+1))break;
36     //标记位恢复原状
37     mark[post] = 1;
38     return 0;
39 }
40 
41 int main()
42 {
43     int count;
44     count = 1;
45     while(scanf("%d",&n)!=EOF)
46     {
47         for(int i = 1; i <= n; i++)
48         mark[i] = i;
49         num[1] = 1;
50         printf("Case %d:
",count++);
51         if(n==1)printf("1
");
52         for(int i = 2;i<=n;i++)
53         dfs(1,i,2);
54         printf("
");
55     }
56     return 0;
57 }
View Code
原文地址:https://www.cnblogs.com/qinduanyinghua/p/5507458.html