现在的位置: 首页 > 综合 > 正文

POJ 2739题解—小菜

2013年01月03日 ⁄ 综合 ⁄ 共 1406字 ⁄ 字号 评论关闭

题意简述

 

              题目要求找出1到10000内数,有多少个素数组成的总数;比如3只有自己那就是3,比如41有2+3+5+7+11+13, 11+13+17,和41,那就是三个(加起来数是连续的素数)


算法分析

 

   主要还是考验如何高效快速的得到素数表.下来就是如何得到开始计算的下标和把所有相加可能得出来。我先用的是朴素的,思考部分加上一些很高效的算法


程序样例


unsigned short IsPrime(unsigned short num)
{
	register unsigned short i=2;
	while(i*i <= num)
	{
		if(num % i == 0)
			break;
		else
			++i;
	}
	if(i*i <= num)
		return 0;
	return 1;
}

int main()
{
	unsigned short i,j,k,counter,tnum,sum;
	unsigned short num[670];
	for(i=2,j=0;i<5000;++i)
	{
		if(IsPrime(i))
			num[++j]=i;
	}
	num[0]=j;
	printf("%u\n",sizeof(short));
	while(1)
	{
		scanf("%hu",&tnum);//between 2 and 10000
		if(tnum == 0)
			return 0;
		counter=0;
		if(tnum > 4999)
		{
			i=num[0];
			if(IsPrime(tnum))
				++counter;
		}
		else
		{
			for(i=1;i<num[0];++i)
			{
				if(num[i] == tnum)
					++counter;
				if(num[i] >= tnum)
				{
					--i;
					break;
				}
			}
		}
		for(k=i;k>0;--k)
		{
			for(j=i,sum=0;j>0;--j)
			{
				sum+=num[j];
				if(sum == tnum)
					++counter;
				if(sum >= tnum)
				{
					--i;
					break;
				}
			}
		}
		printf("%hu\n",counter);
	}

	return 0;
}

流程:

            先把5000内素数,存入数组中,期间算法就是用FOR+朴素的取余判断(效率不高)。下来找到比需要查询数小的数的下标。用来循环判断组成可能。

    NOTE:为什么是5000内呢,因为5000以上的数单独判断就行,要组成的话肯定是两个加和小于10000的组合,所以5000内就够用了

            下来就是两层循环,从刚才下标开始往前加,大了就从前一个重来。直到开始下标小于1

指标:

POJ评定  176K 16MS(诡异的是第一次没改前是0MS)

 

思考

朴素的判断素数确实效率不高,经大大指导 知道了快速点的方法

筛选法

  思路是,要求10000以内的所有素数,把1-10000这些数都列出来,1不是素数,划掉;2是素数,所有2的倍数都不是素数,划掉;取出下一个幸存的数,划掉它的所有倍数;直到所有幸存的数的倍数都被坏掉为止。完成了就可以直接用a[n]
== 1来判断素数了 效率确实很高

    int i, tmp;
    int a[10000]
    memset(a, 0, sizeof(a));
    a[0] = 1;
    a[1] = 1;
    for(i=2;i<10000;i++)
    {
        if(!a[i])
        {
            tmp = i*2;;
            while(tmp < 10000)
            {
                a[tmp] = 1;
                tmp += i;
            }
        }
    }

不过这样出来的素数数组是离散的 中间有很多0 算加和的话,不知道影响大不。但是总体上肯定比我写的效率高~

抱歉!评论已关闭.