hdu1016 Prime Ring Problem dfs 素数打表

意思是给你一个数n,要构成一个素数环,这个素数由1-n组成,它的特征是选中环上的任意一个数字i,i与它相连的两个数加起来都分别为素数,满足就输出。

这个题的做法和hdu1015做法差不多都是使用dfs 回溯。不同之处在于这个要全部搜索,而hdu1015只需要搜索第一组就可以。
其次在这个题目中使用素数打表的方式简化素数判定,在一定情况下也是对效率有所提高的。

Prime Ring Problem
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 34615 Accepted Submission(s): 15331

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

#include 
#include 
#include 
#define maxn 20
using namespace std;
bool dp[maxn][maxn];//记忆素数数组
int n;
bool isvisited[maxn+3];
int m[maxn+3];


void is_prime(){
    for(int i=1;i<20;i++)
        for(int j=1;j<20;j++){
            int test=i+j;
            int flag=0;
            for(int x=2;x*x<=test;x++){
                if(test%x==0){
                    dp[i][j]=false;
                    flag=1;
                    break;
                }
            }
            if(!flag)
                dp[i][j]=true;
    }
}


void pt(){
    int first=0;
    for(int i=1;i<=n;i++){
        if(first)
            printf(" ");
        else
            first=1;
        printf("%d",m[i]);
    }
    printf("\n");
}

void dfs(int k){
    //选到最后一个了
    //肯定不能忘了判定是否与第一个1加起来是素数
    if(k==n&&dp[m[k]][1]){
        //执行打印任务
        pt();
        return ;
    }
    for(int i=2;i<=n;i++)
        //判断这个数用过没有
        if(isvisited[i]==false){
            if(dp[i][m[k]]){//查表,判定加和是否为素数
                isvisited[i]=true;//标记使用状态
                m[k+1]=i;//当前值已经可取
                dfs(k+1);//向下搜索
                isvisited[i]=false;//回溯
            }
        }

}

int main(){
    int ca=1;
    memset(dp,false,sizeof(dp));
    is_prime();//打表
   while(scanf("%d",&n)!=EOF){
         printf("Case %d:\n",ca);
        memset(isvisited,false,sizeof(isvisited));
        m[1]=1;//题目要求第一个必须是1
        dfs(1);//所以我们已经先有一个了,然后向下搜索
        ca++;
        printf("\n");//注意输出完毕以后还有一个空行
   }
   return 0;
}


今天还不错,第一个就ac,相当于lol拿首胜。。哈啊哈

你可能感兴趣的:(oj题解)