| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1795 人关注过本帖
标题:求测试下面程序以及一连串的问题
只看楼主 加入收藏
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
结帖率:99.25%
收藏
已结贴  问题点数:100 回复次数:13 
求测试下面程序以及一连串的问题
因为原题不是正式版~把题目贴出来不太好看,我还是简单描述一下算了~

题目很简短--判断2^62范围内的质数,是就输出yes,不是就输出no

我自己写了个,但由于AC32位不支持long long 型,无法进行高位测试,想知道高位极限测试效率如何~

程序代码:
/*题目,判断2^62范围内的质数--效率至上!!!(我vc不支持long long 型,固无法进行高位测试--有兴趣的可以改改数据类型)*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define STEP 10//选取推导循环步长周期的质数基数(在允许的范围内,STEP越大,遍历时间越短(但预备时间越长),STEP最好不要超过11(不要低于4))
int fun(char *b,int s[]);//求每个步长
int sum(int s[]);//求周期数
void set(int s[]);//求质数基数以及每个质数的数值
int judge_1(int s[],int n);
int judge_2(int s[],int n);
int judge_3(int s[],int n);

int judge_1(int s[],int n)
{
    int i=0;
    for (i=0;i<STEP-3;i++)
        if (n%s[i]==0)
            return 0;

    return 1;
}
int judge_2(int s[],int n)
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n==s[i])
            return 1;

    return 0;
}
int judge_3(int s[],int n)
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n%s[i]==0)
            return 1;

    return 0;
}

int fun(char *b,int s[])
{
    int i=0;
    int a=s[STEP-2];
    char *p=b;
    int kk=sum(s);

    for (i=s[STEP-1];i<=s[STEP-2]+kk;i++)
        if (judge_1(s,i))
        {
            *p++=i-a;//这里用指针能提高运行效率
            a=i;
        }

    return p-b;
}


void set(int s[])
{
    int i=0;
    int j=0;
    int k=0;

    for (i=2;k<STEP;i++)
    {
        for (j=2;j<=(int)sqrt(i);j++)
            if (i%j==0)
                break;

        if (j==(int)sqrt(i)+1)
            s[k++]=i;
    }
}
int sum(int a[])
{
    int i=0;
    int sum=1;
    for (i=0;i<STEP-3;i++)
        sum*=a[i];

    return sum;
}

int main()
{
    char *a=NULL;//char 型看完程序框架分析知道,char型其实存放小数据,能节省空间(虽然还是浪费了不少空间)~

    int step=0;
    int s[STEP]={0};

    int n=0;
    int i=0;
    int flag=0;

    set(s);//求质数基数以及每个质数的数值

    a=(char *)calloc(sum(s),sizeof(char));//使用动态内存分配能最大限度减少空间损失

    step=fun(a,s);

    while (scanf("%d",&n)!=EOF)
    {
        char *p=NULL;//用指针提高运行效率

        flag=1;

        if (n<2)
            flag=0;
        else if (judge_2(s,n))
            flag=1;
        else if (judge_3(s,n))
            flag=0;

        for (i=s[STEP-2],p=a;i<=(int)sqrt(n)&&flag;i+=*p++)
        {
            if (n%i==0)
                flag=0;

            if (p==a+step)
                p=a;
        }

          if (flag)
            printf("yes\n");
        else
            printf("no\n");
    }

    free(a);

    return 0;
}


下面有几个我想解决的问题:
首先,接受极限测试得先把关键数据改为long long 型~

1:算法有没有问题~结果是否会出错~
2:设STEP=10或者STEP=11如果题目要求每组测试数据要在1s内得出正确结果~极限测试会不会超时~
3:STEP 取值感觉取7到11的执行效率都差不多~是不是STEP对执行效率影响不大~还有STEP的最佳取值为多少~
4:听说用指针遍历数组能提高执行效率~但初步尝试用数组和指针效率差不多~事实是不是这个样子的~
5:对这题有没有什么较好的算法~可以拿出来交流一下~


[此贴子已经被作者于2017-1-9 22:11编辑过]

搜索更多相关主题的帖子: include 正式版 极限 如何 
2017-01-09 20:16
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
发现一个严重影响执行效率的问题~~~~

程序代码:
/*题目,判断2^62范围内的质数--效率至上!!!(我vc不支持long long 型,固无法进行高位测试--有兴趣的可以改改数据类型)*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define STEP 10//选取推导循环步长周期的质数基数(在允许的范围内,STEP越大,遍历时间越短(但预备时间越长),STEP最好不要超过11(不要低于4))
int fun(char *b,int s[]);//求每个步长
int sum(int s[]);//求周期数
void set(int s[]);//求质数基数以及每个质数的数值
int judge_1(int s[],int n);
int judge_2(int s[],int n);
int judge_3(int s[],int n);

int judge_1(int s[],int n)
{
    int i=0;
    for (i=0;i<STEP-3;i++)
        if (n%s[i]==0)
            return 0;

    return 1;
}
int judge_2(int s[],int n)
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n==s[i])
            return 1;

    return 0;
}
int judge_3(int s[],int n)
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n%s[i]==0)
            return 1;

    return 0;
}

int fun(char *b,int s[])
{
    int i=0;
    int a=s[STEP-2];
    char *p=b;
    int kk=sum(s);

    for (i=s[STEP-1];i<=s[STEP-2]+kk;i++)
        if (judge_1(s,i))
        {
            *p++=i-a;//这里用指针能提高运行效率
            a=i;
        }

    return p-b;
}


void set(int s[])
{
    int i=0;
    int j=0;
    int k=0;

    for (i=2;k<STEP;i++)
    {
        int kk=(int)sqrt(i);

        for (j=2;j<=kk;j++)
            if (i%j==0)
                break;

        if (j==kk+1)
            s[k++]=i;
    }
}
int sum(int a[])
{
    int i=0;
    int sum=1;
    for (i=0;i<STEP-3;i++)
        sum*=a[i];

    return sum;
}

int main()
{
    char *a=NULL;//char 型看完程序框架分析知道,char型其实存放小数据,能节省空间(虽然还是浪费了不少空间)~

    int step=0;
    int s[STEP]={0};

    int n=0;
    int i=0;
    int flag=0;

    set(s);//求质数基数以及每个质数的数值

    a=(char *)calloc(sum(s),sizeof(char));//使用动态内存分配能最大限度减少空间损失

    step=fun(a,s);

    while (scanf("%d",&n)!=EOF)
    {
        char *p=NULL;//用指针提高运行效率
        int ss=(int)sqrt(n);

        flag=1;

        if (n<2)
            flag=0;
        else if (judge_2(s,n))
            flag=1;
        else if (judge_3(s,n))
            flag=0;

        for (i=s[STEP-2],p=a;i<=ss&&flag;i+=*p++)
        {
            if (n%i==0)
                flag=0;

            if (p==a+step)
                p=a;
        }

          if (flag)
            printf("yes\n");
        else
            printf("no\n");
    }

    free(a);

    return 0;
}



//for (i=s[STEP-2],p=a;i<=(int)sqrt(n)&&flag;i+=*p++)//改了这里,竟然快了不少,极限测试时这个地方要特别注意~~~~

[此贴子已经被作者于2017-1-9 22:54编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-01-09 22:25
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10566
专家分:43004
注 册:2014-5-20
收藏
得分:20 
4:听说用指针遍历数组能提高执行效率~但初步尝试用数组和指针效率差不多~事实是不是这个样子的~
这点不好说/
如果只是对 *p 与 a[i] 来说,p是绝对地址,而a[i]的a是基址、i是偏移量。从寻址来看理应p比a[i]快,但实际如何,可能说不定,这是否与电脑的运算器和控制器或不同区域寻址方式有关。
如果是 *(p+i) 与 a[i]应该无什么差别吧?
2017-01-09 23:29
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
继续优化代码~主要是减少判断次数~用结构体变量能减少传参~提高执行效率~

程序代码:
/*题目,判断2^62范围内的质数--效率至上!!!(我vc不支持long long 型,固无法进行高位测试--有兴趣的可以改改数据类型)*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define STEP 10//选推导循环步长周期的质数基数(在允许的范围内,STEP越大,遍历时间越短(但预备时间越长),STEP最好不要超过11(不要低于4))
typedef struct Node
{
    char *a;//char 型看完程序框架分析知道,char型其实存放小数据,能节省空间(虽然还是浪费了不少空间)~
    int step;
    int s[STEP];
}Node;
Node S={0};

int n=0;

int fun();//求每个步长
int sum();//求周期数
void set();//求质数基数以及每个质数的数值
int judge_1(int n);
int judge_2();
int judge_3();
int judge_main();

int judge_1(int n)
{
    int i=0;
    for (i=0;i<STEP-3;i++)
        if (n%S.s[i]==0)
            return 0;

    return 1;
}
int judge_2()
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n==S.s[i])
            return 1;

    return 0;
}
int judge_3()
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n%S.s[i]==0)
            return 1;

    return 0;
}

int fun()
{
    int i=0;
    int a=S.s[STEP-2];
    char *p=S.a;
    int kk=sum();
    int ss=S.s[STEP-2]+kk;

    for (i=S.s[STEP-1];i<=ss;i++)
        if (judge_1(i))
        {
            *p++=i-a;     //这里用指针能提高运行效率
            a=i;
        }

    return p-S.a;
}


void set()
{
    int i=0;
    int j=0;
    int k=0;

    for (i=2;k<STEP;i++)
    {
        int kk=(int)sqrt(i);

        for (j=2;j<=kk;j++)
            if (i%j==0)
                break;

        if (j==kk+1)
            S.s[k++]=i;
    }
}
int sum()
{
    int i=0;
    int sum=1;
    for (i=0;i<STEP-3;i++)
        sum*=S.s[i];

    return sum;
}
int judge_main()
{
        int i=0;
        char *p=NULL;//用指针提高运行效率
        char *a=S.a;
        int step=S.step;

        int ss=(int)sqrt(n);

        if (judge_3()&&judge_2()==0)
            return 0;

        for (i=S.s[STEP-2],p=a;i<=ss;i+=*p++)
        {
            if (n%i==0)
                return 0;

            if (p==a+step)
                p=a;
        }

        return 1;
}

int main()
{
    int k=0;
    set(S.s);//求质数基数以及每个质数的数值

    S.a=(char *)calloc(sum(),sizeof(char));//使用动态内存分配能最大限度减少空间损失

    S.step=fun();

    while (scanf("%d",&n)!=EOF)
    {
        if (judge_main()&&n!=1)
        {
            printf("yes\n");
            continue;
        }

       printf("no\n");
    }

    free(S.a);

    return 0;
}





[此贴子已经被作者于2017-1-10 02:52编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-01-09 23:30
azzbcc
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:江西财经大学
等 级:贵宾
威 望:81
帖 子:3293
专家分:12919
注 册:2012-11-4
收藏
得分:0 
VC不支持 long long ,但它有个 __int64,你的算法还没看明白


[fly]存在即是合理[/fly]
2017-01-10 09:44
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 5楼 azzbcc
哇,看来我还是低估了算法理解难度了算法还是以四楼为佳~有时间我尽量写详细注释。大体思路是这样的,判断质数要尽量减少耗时,只需判断它是否被小于它的一个质数(不等于1)整除,尽量跳开合数判断。例如,只需判断该数是否能被2 3 5 7 11……整除~以上面5个参与整除的质数为例,2*3*5*7*11为一个判断周期,在一个判断周期里面,跳过被2 3 5 7 11自身及其整除的合数就行了,然后再进一步筛选~思路应该不难理解我想是变量包装变样影响了程序的可读性~

[此贴子已经被作者于2017-1-10 10:46编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-01-10 10:22
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:30 
感觉不用看题主算法,肯定效率低下。下述代码会找到2^62以内最大的素数(4611686018427387847),用时超过15秒,这种效率都这样,就不谈题主用数组了。
大致想了下素数快速算法,还是应该建立素数表,但不是筛法,因为无法申请到超过2G(sqrt(2^62)=2^31,在正常的int数据范围内)的筛法表内存。利用任何合数都可以分解为素数因子的规则,在2G范围内的素数个数不超过100000(我估计的)的实际情况,建立的素数表后每次判断的比较的次数少于100000,将极大提高判断效率。
程序代码:
#include <stdio.h>
int ispri(_int64 n)
{
    _int64 i;
    for(i=2;i*i<=n&&n%i;i++);
    return i*i>n;
}
void main()
{
    _int64 a=4611686018427387904;
    while(!ispri(a))a--;
    printf("%I64d\n",a);
}
2017-01-10 10:47
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 7楼 xzlxzlxzl
我想有你这个思想基础下我的算法就容易理解多了~其实预先从文件读入一个素数表(1000w内的质合比约为1:16,2^31--20多亿的质合比应该更低,估计素数在10000w左右)效率最佳(可惜AC不允许文件读入)~

建立素数表的前提是要先遍历素数表范围内的数据一遍,可以提高连续测试数据的执行效率,但是,对单个数据的判断是没多大意义的,因为建立素数表的时间是不能省的~

于是我想到了建立了一个"伪素数间距表",在"伪素数间距表",可以顾名思义理解一下--结合本例该表--里前n项的和必然不是选定质数基数的倍数,再以2 3 5 7 11为例,"伪素数间距周期表"里面前n项之和必然不是2 3 5 7 11除了它们自身外的其中之一的倍数,该表的每个数值代表相邻两个伪质数的间距,该表长度为所有数值和等于2*3*5*7*11时的长度,即表示1个周期,判断质数时只需每次相加表里面的数值就行了~

可以通过(2*3*5*7*11)/表长  算出平均步长~

就以本题为例,当STEP=10时,平均步长约为5.5,意义即为每次判断i的平均自增量为5.5,对于一个质数n,最多判断(int)sqrt(n)/5.5  次~~~



[此贴子已经被作者于2017-1-10 14:11编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-01-10 11:12
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
下面这个为测试代码(看来还是有可能超时不过假如允许从文件里面读入素数表这个问题就解决了)~~

程序代码:
/*题目,判断2^62范围内的质数--效率至上!!!(我vc不支持long long 型,固无法进行高位测试--有兴趣的可以改改数据类型)*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define STEP 11//选推导循环步长周期的质数基数(在允许的范围内,STEP越大,遍历时间越短(但预备时间越长),STEP最好不要超过11(不要低于4))
typedef struct Node
{
    char *a;//char 型看完程序框架分析知道,char型其实存放小数据,能节省空间(虽然还是浪费了不少空间)~
    int step;
    int s[STEP];
}Node;
Node S={0};
unsigned long long int n=(unsigned long long int)pow(2,62);
int fun();//求每个步长
int sum();//求周期数
void set();//求质数基数以及每个质数的数值
int judge_1(int n);
int judge_2(int n);
int judge_3(int n);
int judge_main();

int judge_1(int n)
{
    int i=0;
    for (i=0;i<STEP-3;i++)
        if (n%S.s[i]==0)
            return 0;

    return 1;
}
int judge_2()
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n==S.s[i])
            return 1;

    return 0;
}
int judge_3()
{
    int i=0;
    for (i=0;i<STEP-2;i++)
        if (n%S.s[i]==0)
            return 1;

    return 0;
}

int fun()
{
    int i=0;
    int a=S.s[STEP-2];
    char *p=S.a;
    int kk=sum();
    int ss=S.s[STEP-2]+kk;

    for (i=S.s[STEP-1];i<=ss;i++)
        if (judge_1(i))
        {
            *p++=i-a;     //这里用指针能提高运行效率
            a=i;
        }

    return p-S.a;
}


void set()
{
    int i=0;
    int j=0;
    int k=0;

    for (i=2;k<STEP;i++)
    {
        int kk=(int)sqrt(i);

        for (j=2;j<=kk;j++)
            if (i%j==0)
                break;

        if (j==kk+1)
            S.s[k++]=i;
    }
}
int sum()
{
    int i=0;
    int sum=1;
    for (i=0;i<STEP-3;i++)
        sum*=S.s[i];

    return sum;
}
int judge_main()
{
        long long int i=0;
        char *p=NULL;//用指针提高运行效率
        char *a=S.a;
        int step=S.step;

        unsigned long long int ss=(unsigned long long int)sqrt(n);

        if (judge_3()&&judge_2()==0)
            return 0;

        if (n<2)
            return 0;

        for (i=S.s[STEP-2],p=a;i<=ss;i+=*p++)
        {
            if (n%i==0)
                return 0;

            if (p==a+step)
                p=a;
        }

        return 1;
}

int main()
{
    set();//求质数基数以及每个质数的数值

    S.a=(char *)calloc(sum(),sizeof(char));//使用动态内存分配能最大限度减少空间损失

    S.step=fun();

    while (n--)
    {
        if (judge_main())
        {
            printf("%llu yes\n",n);
            continue;
        }

        printf("%llu no\n",n);
    }

    free(S.a);

    return 0;
}

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-01-10 12:06
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
有了上面测试代码~发现STEP的取值的确对运行时间有影响,但这样优化还远远达不到1SEC内得出结果的目的~

建立素数表无论是在空间上还是时间上,空间*时间是不能省的功,要得出2^31内的所有素数,需要先初始化一遍~

感觉如何缩短建立素数表的时间是一个关键的问题~

素数表出来了,问题就解决了~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-01-10 13:29
快速回复:求测试下面程序以及一连串的问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.020301 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved