• 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
  • 相关阅读:
    如何用RadioButton做一个底部的切换栏
    自定义有监听器的ScrollView
    ViewPager的使用小技巧
    什么时候用Application的Context,什么时候用Activity的Context
    让改变输入法回车键的图标
    墙内下载DropBox离线安装包的方法
    巧用用layer-list做一个卡片背景
    LeakCanary中英文文档+使用例子
    让你的APK瘦成一道闪电
    用一张图片实现按钮按下和普通效果的样式
  • 原文地址:https://www.cnblogs.com/qinduanyinghua/p/5507458.html
Copyright © 2020-2023  润新知