Prime Ring Problem

原题:hdoj 1016

原题大意

图1
如图,6个数收尾相连,任意两个相邻的数之和是质数.现在请你输入数字n,表示从1到n的整数,将它们排列成一个环,形成如图所示的质数环.

算法分析

用dfs遍历每种情况

代码程序

程序1

#include <stdio.h>
#include <math.h>
#include <memory.h>
#define N 20
int a[N],b[N];
int n;
int c=0;
int is_prime(int t)//判断是否是质数
{
    int i;
    if(t==1)    return 0;
    for(i=2;i<=sqrt(t);i++)
    {
        if(t%i==0)    return 0;    
    }
    return 1;    
}
int check(int t,int m)//检查有没有与之前的数重复
{
    int i;
    for(i=0;i<m;i++)
        if(t==b[i])
            return 0;
    return 1;
}
void ring(int num)
{
    int i;
    if(num==n&&is_prime(b[n-1]+1))    //最后要与第一个数连起来
    {
        for(i=0;i<n-1;i++)
            printf("%d ",b[i]);//!此处输出格式很重要
            printf("%d",b[i]);
        printf("\n");
    }
    else
    {
        for(i=1;i<n;i++)
            {
                if(check(a[i],num)&&is_prime(a[i]+b[num-1]))
                    {
                        b[num]=a[i];
                        ring(num+1);    
                    }    

            }
    }
}
int main()
{
    int i;
    while(scanf("%d",&n)!=EOF)
    {
        c++;
        printf("Case %d:\n",c);
        for(i=0;i<n;i++)
        {
            a[i]=i+1;
        }
        memset(b,0,sizeof(b));
        b[0]=1;
        ring(1);
        printf("\n");
    }
    return 0;
}

程序2

#include <stdio.h>
#include <math.h>
#include <memory.h>
#define N 20
int a[N];
int b[N]={0};//记录a中对应的数有没有被用过
int n;
int c=0;
int is_prime(int t)//同上
{
    int i;
    if(t==1)    return 0;
    for(i=2;i<=sqrt(t);i++)
    {
        if(t%i==0)    return 0;    
    }
    return 1;    
}
void ring(int num)//同上
{
    int i;
    if(num==n&&is_prime(a[num-1]+1))
    {
        for(i=0;i<n-1;i++)
        {
            printf("%d ",a[i]);
        }
            printf("%d",a[i]);
        printf("\n");
    }
    else
    {
        for(i=2;i<=n;i++)
        {
            if(!b[i]&&is_prime(i+a[num-1]))
                {
                    a[num]=i;
                    b[i]=1;
                    ring(num+1);
                    b[i]=0;//一定要改回来
                }
        }
    }
}
int main()
{
    int i;
    while(scanf("%d",&n)!=EOF)
    {
        c++;
        printf("Case %d:\n",c);
        memset(b,0,sizeof(b));
        a[0]=1;
        ring(1);
        printf("\n");
    }
    return 0;
}

注意事项

由于这是acm题,所以输入输出的格式很重要,我的代码里有一段是这样写的:

if(num==n&&is_prime(a[num-1]+1))
    {
        for(i=0;i<n-1;i++)
            printf("%d ",a[i]);
        printf("%d",a[i]);
        printf("\n");
    }

看上去很奇怪,因为一般我是这样写的:

if(num==n&&is_prime(a[num-1]+1))
{
    for(i=0;i<n;i++)
        printf("%d ",a[i]);
    printf("\n");
}

这是因为每行数据的最后一个输出的数后不用空格,否则就算格式不对.

总结

我写了两段代码,这两段代码都AC了,区别有两处:

  • 检查重复的方法不一样,第一种是写了个函数,第二种是用数组保存.
  • 第一种用了数组保存前n个数,第二种是边选边填.

所以,综合下来,第二段代码更好一些,占的内存和运行时间也更快.