nyist-素数环

来源:互联网 发布:python 字典遍历 编辑:程序博客网 时间:2024/05/18 01:39

素数环

时间限制:1000 ms  |  内存限制:65535 KB
难度:2
描述

有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻两个数(包括首尾)的和都为素数,称为素数环。

为了简便起见,我们规定每个素数环都从1开始。例如,下图就是6的一个素数环。

输入
有多组测试数据,每组输入一个n(0<n<20),n=0表示输入结束。
输出
每组第一行输出对应的Case序号,从1开始。
如果存在满足题意叙述的素数环,从小到大输出。
否则输出No Answer。
样例输入
6830
样例输出
Case 1:1 4 3 2 5 61 6 5 2 3 4Case 2:1 2 3 8 5 6 7 41 2 5 8 3 4 7 61 4 7 6 5 8 3 21 6 7 4 3 8 5 2Case 3:No Answer


开始一上来的思路就是列出所有情况~~~啥都不管直接找

但是想想    6个数组成的6位数  有  6!个

n=20 时  20!一个一个找 ?能不超时?

剪枝,把两边和不是素数去掉  合理  可以

好了 经过我认真分析发现素数和跟我写的zb和 部分和 有一点很大的不同

比如我在部分和中   发现这个数不行 溯回后 再向下查找时  这个数后面就不用了

比如例子   

3  21

5 8 13

第一遍  找了  5 8 13  发现不行  回溯  到8 还不行  回溯到  5  还不行回溯  从8开始(8为第一个数)  

后面就不用5了

而这个素数和不一样,接下来的搜索 还我要用  还要思考如何在后面继续用到这个数

那我用过就把这个数标记了,如果回溯就取消标记

for循环的时候从头循环

for(int i=pos; i<n; i++)      {          sum+=a[i];          visit[i]=1;          /*printf("%d %d %d\n",pos,i,sum);         for(int k=0; k<n; k++)         {             printf("%d ",visit[k]);         }         printf("\n");*/          dfs(i+1);          sum-=a[i];          visit[i]=0;      }  

这是部分和问题的中的for循环  从当前递归的数 的下一位开始   前面的数都不用了

好了  素数环要改变策略了  


#include<stdio.h>#include<math.h>#include<string.h>int a[30],b[30];int n,j;bool flag;/*int ss(int x){    int l=1;    if(x==0||x==1)    {        x=0;    }    for(int i=2; i<=sqrt(x); i++)    {        if(x%i==0)        {            l=0;        }    }    return l;}*/void dfs(int x){    /*if(ss(a[j]+a[j-1])!=1)    {           return;                                                                                                                                            }*/    if(x>n)    {        for(int i=1; i<=n; i++)        {            printf("%d ",b[i]);        }        printf("\n");        return ;    }    for(int i=1; i<n; i++)    {        if(a[i]==0)        {            printf("%d$\n",x);            a[i]=1;    //  标记 表示这个数用过            b[j++]=x; //将当期数存入b中            for(int i=1; i<=n; i++)            {                printf("%d ",b[i]);            }            printf("*\n");            dfs(i+1);            b[--j]=0;            a[i]=0;     //去掉标记            for(int i=1; i<=n; i++)            {                printf("%d ",b[i]);            }            printf("**\n");        }    }}int main(){    while(scanf("%d",&n)!=EOF)    {        if(n==0)        {            break;        }        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        flag=false;        j=1;        dfs(1);    }}


好了  我写的代码  输出没结果  尴尬

这样  一步一步来  先来输出所有的情况 再判断那种符合条件

那咱们先找出所有的情况  其他的不考虑

简单化 

简单化的过程中发现了自己的一个思维错误

(这就是自己dbug的好处)

如果这样写递归 永远也出不了结果

为什么那

我输入3

递归是从第二个数  2 开始的

进去后发现到了x=2  就return  了

虽然我都没用return 

过程中根本就没输出结果

改了一下

 for(int i=1; i<=n; i++)    {        if(a[i]==0)        {            printf("%d$\n",x);            a[i]=1;    //  标记 表示这个数用过            b[j++]=x; //将当期数存入b中

发现有一种情况可以输出  但是另外的情况的最后的一个数都输不出来

推理一下  可能是回溯的问题

又修改了一个地方  原来的

dfs(i+1)
改为
dfs(x+1)
好了   就可以输出所有排序情况

代码

#include<stdio.h>#include<math.h>#include<string.h>int a[30],b[30];int n,j;bool flag;/*int ss(int x){    int l=1;    if(x==0||x==1)    {        x=0;    }    for(int i=2; i<=sqrt(x); i++)    {        if(x%i==0)        {            l=0;        }    }    return l;}*/void dfs(int x){    /*if(ss(a[j]+a[j-1])!=1)    {           return;                                                                                                                                            }*/    if(x>n)    {        for(int i=1; i<=n; i++)        {            printf("%d ",b[i]);        }        printf("\n");        return ;    }    for(int i=1; i<=n; i++)    {        if(a[i]==0)        {            //printf("%d$\n",x);            a[i]=1;    //  标记 表示这个数用过            b[j++]=i; //将当期数存入b中            /*for(int i=1; i<=n; i++)            {                printf("%d ",a[i]);            }            printf("*\n");*/            dfs(x+1);            b[--j]=0;            a[i]=0;     //去掉标记            /*for(int i=1; i<=n; i++)            {                printf("%d ",a[i]);            }            printf("**\n");*/        }    }}int main(){    while(scanf("%d",&n)!=EOF)    {        if(n==0)        {            break;        }        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        //flag=false;        j=1;        dfs(1);    }}
纯手工  自己想 ,自己dbug  真不容易!!!!!

分析一下为什么这样改  还有为什么会在2时候就return

如果  是 dfs(i+1)的话如果我第二个数选3  即选了  1 3  

本来该选3  了  可是我dfs(i+1) 就是dfs(4) 就符合return条件了

直接跳出

下面添枝加叶就完成这道题了


#include<stdio.h>#include<math.h>#include<string.h>int a[30],b[30];int n,j;bool flag;int ss(int x){    int l=1;    if(x==0||x==1)    {        x=0;    }    for(int i=2; i<=sqrt(x); i++)    {        if(x%i==0)        {            l=0;        }    }    return l;}void dfs(int x){    if(a[1]!=1)    {        return;    }    if(ss(a[j]+a[j-1])!=1&&j>1)    {           return;                                                                                                                                           }    if(x>n)    {        flag=true;        for(int i=1; i<=n; i++)        {            printf("%d ",b[i]);        }        printf("\n");        return ;    }    for(int i=1; i<=n; i++)    {        if(a[i]==0)        {            //printf("%d$\n",x);            a[i]=1;    //  标记 表示这个数用过            b[j++]=i; //将当期数存入b中            /*for(int i=1; i<=n; i++)            {                printf("%d ",a[i]);            }            printf("*\n");*/            dfs(x+1);            b[--j]=0;            a[i]=0;     //去掉标记            /*for(int i=1; i<=n; i++)            {                printf("%d ",a[i]);            }            printf("**\n");*/        }    }}int main(){    while(scanf("%d",&n)!=EOF)    {        if(n==0)        {            break;        }        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        flag=false;        j=1;        dfs(1);        if(!flag)        {            printf("No Answer\n");        }    }}

输出的全是No Answer

无语...........

发现了

 if(a[1]!=1)    {        return;    }

这个判断语句是有毛病的  我第一次进来

直接就return回去了  因为  a【1】还是0那   直接我就不递归了  那不就WA了

修改后代码

#include<stdio.h>#include<math.h>#include<string.h>int a[30],b[30];int n,j,step=0,time;bool flag;int jude(int a){    int p=1;    if(a==1||a==0)    {        return 0;    }    for(int i=2; i<=sqrt(a); i++)    {        if(a%i==0)        {            p=0;        }    }    return p;}void dfs(int x){    if(j>=2&&jude(b[j-1]+b[j-2])!=1)    {        return;    }    if(x>=n&&jude(b[n-1]+1)!=1)    {        return;    }    if(x>=n)    {        if(time==1)        {            printf("Case %d:\n",step);            time++;        }        for(int i=0; i<n; i++)        {            printf("%d ",b[i]);        }        printf("\n");        flag=true;        return ;    }    for(int i=2; i<=n; i++)    {        if(a[i]==0)        {            a[i]=1;    //  标记 表示这个数用过            b[j++]=i; //将当期数存入b中            dfs(x+1);            b[--j]=0;            a[i]=0;     //去掉标记        }    }}int main(){    while(scanf("%d",&n)!=EOF)    {        step++;        if(n==0)        {            break;        }        memset(a,0,sizeof(a));        b[0]=1,b[1]=2;        j=1,time=1;        flag=false;        dfs(1);        if(!flag)        {            printf("Case %d:\n",step);            printf("No Answer\n");        }    }    return 0;}

万事OK   提交

TL  超时!!

好了   发现一个规律  

凡是奇数的  都是  no answer

因为奇数个数的数 组成环  必须会有2个奇数组合在一起

奇数加奇数为偶数  直接就不是素数了

再提交   

猝不及防  一个WA   

因为   当n=1时  应该输出1  

这输出的  no answer

╮(╯▽╰)╭

AC代码

#include<stdio.h>#include<math.h>#include<string.h>int a[30],b[30];int n,j,step=0,time;bool flag;int jude(int a){    int p=1;    if(a==1||a==0)    {        return 0;    }    for(int i=2; i<=sqrt(a); i++)    {        if(a%i==0)        {            p=0;        }    }    return p;}void dfs(int x){    if(j>=2&&jude(b[j-1]+b[j-2])!=1)    {        return;    }    if(x>=n&&jude(b[n-1]+1)!=1)    {        return;    }    if(x>=n)    {        if(time==1)        {            printf("Case %d:\n",step);            time++;        }        for(int i=0; i<n; i++)        {            printf("%d ",b[i]);        }        printf("\n");        flag=true;        return ;    }    for(int i=2; i<=n; i++)    {        if(a[i]==0)        {            a[i]=1;    //  标记 表示这个数用过            b[j++]=i; //将当期数存入b中            dfs(x+1);            b[--j]=0;            a[i]=0;     //去掉标记        }    }}int main(){    while(scanf("%d",&n)!=EOF)    {        step++;        if(n==0)        {            break;        }        if(n==1)        {            printf("Case %d:\n",step);            printf("1\n");            continue;        }        if(n%2==1)        {            printf("Case %d:\n",step);            printf("No Answer\n");            continue;        }        memset(a,0,sizeof(a));        b[0]=1,b[1]=2;        j=1,time=1;        flag=false;        dfs(1);        if(!flag)        {            printf("Case %d:\n",step);            printf("No Answer\n");        }    }    return 0;}


总结   

小白我 明白了  memset  只能把数组重置为  0 或者  -1  其他的都是乱码

还有  做题  从基础的开始  

一道题也许对你很难

那你一步一步实现

就如这一题  

先找出所有情况,再排除一些













0 0
原创粉丝点击