A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

本帖最后由 大虾挂了 于 2013-11-3 05:11 编辑

求1-100内所有素数的和么?我认为这里最快的方法涉及到2个问题,一个i是判断因子的时候,究竟要判断哪些数字,另一个是究竟判断到什么位置就OK。

1、合数必然能分解成一些素数的乘积,这是其一,所以判断因子的时候只需判断素数即可。没必要2、3、4、5、6。。。。。。连续判断
如果这里不理解,举几个例子,比如判断完2不是num的因子,那么4、6、8。。。。一系列数都不用判断了,因为2是后面一系列数的公因子,如果连2都除不开,还想除开后面的显然是不可能的。同理,判断完3,那6、9、12、15。。。。。。。一系列数也不用判断了。说白了,只要可拆的数都不用判断,因为我们之前判断过他的某个因子了。也就是只要是合数就没i要判断。
(原本对于单纯的给定一个数,判断是否是素数,这一条意义不大,毕竟我们无法知晓比给定数字小的素数有哪些,但是这里由于要求和,这一条就有意义了,后面举例说明)

2、对于一个数字n,我们究竟验证因子时,验证到多大的时候就可以确定这个数字是素数了呢?答案是n开平方。
解释下原因。假设n是合数,那么n必然能拆成为2个因子相乘n=a*b,a和b均不为1。我们验证的时候极限位置是什么呢,应该是“n的最小因子,最大可能取的值”,这个值刚好就是n开平方。
如果这样说不理解,用另外的方法说明,我们找到a和b中比较小的那个数字,不妨假设a是比较小的,我们让a大于根号n,由于设定上b要大于等于a,所以b大于根号n,两个大于根号n的数相乘,所以a*b是大于n的,与提干等于n矛盾,反证法证明,这两个因子中,最小的那个一定不会超过根号n,极限条件是a和b同时取根号n。也就是说,当我们验证因子的时候,如果验证到了根号n,依然没有找到因子,就说明这个数没有最小因子(除1以外),能拆则必然有最小,哪怕是两个因子相等,那也是两个因子都是最小因子,找不到最小因子,意味着不能拆,也就意味着没有因子,是素数。
我们平时使用的验证方法其实是以找n 最大因子的最大极限来判断的。

这里综合上面两个方法举个例子。
比如验证29。首先根号29=5,所以我们要验证的仅仅5以内的素数是否是29的因子。之前我们每次检测到一个素数都要放入一个集合中,这个集合中小于等于5的数有2、3和5,所以只需验证这3个因子,验证完发现他们都不是29的因子,那么得出结论,29是素数,然后把它丢到素数集合中去

结合上面两条,求1~n内所有素数的和,采用如下方法:
1、首先定义一个集合来存放检索到的素数(定义数组也可以,不过数组长度要足够长,又不要过分长,我们可以用n/(ln n)-1来作为这个数组的长度)
2、搜索素数填入集合中,检索方式采用上面说的
3、计算1集合中所有元素的和(采用数组的话就可以添加是否为0的判断来终止求和,毕竟素数不会装满1中数组的)

代码一会儿贴下

评分

参与人数 1技术分 +1 收起 理由
追溯客 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 大虾挂了 于 2013-11-3 06:04 编辑
  1. using System;
  2. using System.Collections.Generic;

  3. namespace 求1_n的所有素数和
  4. {
  5.     class Program
  6.     {
  7.         static void Main(string[] args)
  8.         {
  9.             //定义一个集合来存放素数,初始状态给集合填入一个2
  10.             List<int> sushu = new List<int>();
  11.             sushu.Add(2);

  12.             Console.WriteLine("请输入一个大于2的数,我们将给出小于等于这个数的所有素数的和");
  13.             int n = Convert.ToInt32(Console.ReadLine());
  14.             //j作为内层循环中,因子检测的sushu集合中的索引.ans用于存储结果
  15.             int j = 0,ans=0;

  16.             for (int i = 3; i < n + 1; i++)
  17.             {
  18.                 //一个数的最小因子,最大不会超过这个数开平方,所以这个数开平方即是验证因子的极限
  19.                 for (j=0; sushu[j] <= Math.Sqrt(i); j++)
  20.                 {
  21.                     //如果这个数能整除集合中的某个数,则证明这个数是合数
  22.                     if (i % sushu[j] == 0)
  23.                         break;
  24.                 }
  25.                 //如果上面的循环没有通过break跳出,下面的条件必然成立,则意味着这个i是素数、
  26.                 //注意,对于3这个素数,根本没有经历过上面循环,这是个特例
  27.                 if (sushu[j] > Math.Sqrt(i))
  28.                     sushu.Add(i);
  29.             }
  30.             //Console.WriteLine("以下是满足条件的所有素数");
  31.             //foreach (int a in sushu)
  32.             //{
  33.             //    Console.Write(a.ToString() + "\t");
  34.             //}
  35.             for (int i = 0; i < sushu.Count; i++)
  36.             {
  37.                 ans+=sushu[i];
  38.             }
  39.             Console.Write("小于等于{0}的所有素数的和为:",n.ToString());
  40.             Console.WriteLine(ans);
  41.             Console.ReadKey();
  42.         }
  43.     }
  44. }
复制代码
这是用我上面说的思路写的代码

评分

参与人数 1技术分 +1 收起 理由
陈福军 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马