goj 素数环(dfs)

Problem Description:

如图所示,环由n个圆组成。 将自然数1,2,...,n分别放入每个圆中,并且两个相邻圆中的数字总和应为素数。

注意:第一个圆圈的数量应该始终为1。

Input:

n (0 < n < 20). 

Output:

输出格式如下所示。 每行代表从1开始顺时针和逆时针旋转的一系列圆圈数字。 数字的顺序必须符合上述要求。 按照字典顺序打印解决方案。

你要编写一个完成上述过程的程序。

即使没有答案,也会在每个案例后打印一个空行。

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
解题思路:dfs。先打表记录40以内是素数的数组isp,因为相邻数之和有可能最大为39,所以只需枚举到39。关于字典序输出,这里每枚举到当前这个数,从2开始到n枚举哪些数是满足条件,有的话就将当前这个数记录在path数组中,并且标记这个数已经被访问,再递归下去寻找下一个数,如果递归不满足条件的话,将当前这个数置为0。每当cur==n时就输出当前素数环。其中有一个剪枝的操作,如果给定的整数n为奇数,那么肯定不存在素数环,(因为肯定存在两个奇数相邻,而奇数与奇数的和为偶数,所以一定不是素数环)这个节省了不少递归时间,不然老是TLE-_-||。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,isp[40]={0},vis[20],path[20];//vis数组是保存标记,path是记录
 4 int is_prime(int t)//判断素数
 5 {
 6     for(int i=2;i*i<=t;++i)
 7         if(t%i==0)return 0;
 8     return 1;
 9 }
10 void dfs(int cur)
11 {
12     if((cur==n) && isp[path[1]+path[n]]){//递归边界 如果cur==n && isp(1+path[n])是素数,则终止条件
13         for(int i=1;i<n;i++)
14             cout<<path[i]<<' ';
15         cout<<path[n]<<endl;
16         return ;
17     }
18     else{
19         for(int i=2;i<=n;++i){//尝试放置每个数i
20             if(!vis[i] && isp[i+path[cur]]){  //如果i没用过
21                 path[cur+1]=i;//且i加上与之相邻的上一个数之和是素数,则把它赋给path[cur+1];
22                 vis[i]=1; //设置使用标志
23                 dfs(cur+1); //深搜
24                 vis[i]=0; //清除标志
25             }
26         }
27     }
28 }
29 int main()
30 {
31     for(int i=2;i<40;++i)  //生成素数表,枚举到最大的2倍即可
32         isp[i]=is_prime(i);
33     int k=1;     //Case情况数
34     while(cin>>n){
35         cout<<"Case "<<k++<<':'<<endl;
36         memset(vis,0,sizeof(vis));
37         vis[1]=1,path[1]=1;//将1作为path开头,且标记已访问
38         if(n>0 && (n%2==0))dfs(1);//剪枝,如果是偶数的话,必有素数环,从1开始深搜
39         cout<<endl;
40     }
41     return 0;
42 }
 
posted @ 2018-04-12 22:45  霜雪千年  阅读(775)  评论(0编辑  收藏  举报