当前位置:   article > 正文

素数距离问题--以为存储素数表会更快,结果sqrt更快

找素数 i*i 和sqrt谁快

地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=24

素数距离问题

时间限制:3000 ms  |  内存限制:65535 KB
难度:2
描述
现在给出你一些数,要求你写出一个程序,输出这些整数相邻最近的素数,并输出其相距长度。如果左右有等距离长度素数,则输出左侧的值及相应距离。
如果输入的整数本身就是素数,则输出该素数本身,距离输出0
输入
第一行给出测试数据组数N(0<N<=10000)
接下来的N行每行有一个整数M(0<M<1000000),
输出
每行输出两个整数 A B.
其中A表示离相应测试数据最近的素数,B表示其间的距离。
样例输入
3
6
8
10
样例输出
5 1
7 1
11 1

思路:

一开始想到的是用一个素数表来存储,用猜想6N+-1的原则,只需要算到6N+5的时候,就足够判断是中间,左边,还是右边了。用到厄拉多塞筛法,两个for,一步步乘以质数,将非质数排除,最后直接往两边找就可以了。结果全超时了。。

原本想用sqrt,想着重复算sqrt(左,中,右)会比较慢。结果看到讨论区,用这种方法做c的,能ac。我也试着用java,发现也可以。很费解,原以为sqrt慢,结果更快了。

无奈之下,只好演算下,发现3*sqrt(m)[最好情况]总是会小于m+5的,加上讨论区,有人把所以范围内的素数输出来,发现,绝大部分距离在0-2之间。当m=10000时,假设5*sqrt(m)也会小于m+5.总是会存储素数表的快。

这是讨论区的,将c改java

  1. public static void sqrtPrimesMinDistance1(int m) {
  2. int tmpR, tmpL, minR, minL;
  3. minR = minL = 0;
  4. tmpR = tmpL = m;
  5. while (true) {
  6. if (isPrimes(tmpL)) {
  7. System.out.println(m - minL + " " + minL);
  8. break;
  9. }
  10. if (isPrimes(tmpR)) {
  11. System.out.println(m + minR + " " + minR);
  12. break;
  13. }
  14. tmpL--;
  15. tmpR++;
  16. minL++;
  17. minR++;
  18. }
  19. }
原本以为他没有考虑到左距离和右距离的比较久直接跳出了,还以为是测试数据有bug。后面才发现,这里设计得很巧妙。用了两个if,先判左边,如果右边相同就取左边,若小也取左边,也刚好就break。两个符合情况,就判下一个右边的if。结果就很符合题意了。

而我写的

  1. public static void sqrtPrimesMinDistance2(int m) {
  2. int tmpR, tmpL, minR, minL;
  3. minR = minL = m;
  4. tmpR = tmpL = m;
  5. if (isPrimes(m)) {
  6. System.out.println(m + " 0");
  7. return;
  8. }
  9. while (true) {
  10. if (isPrimes(tmpL)) {
  11. minL = m - tmpL;
  12. }
  13. if (isPrimes(tmpR)) {
  14. minR = tmpR - m;
  15. }
  16. if (minR != m || minL != m) {
  17. if (minL <= minR)
  18. System.out.println(tmpL + " " + minL);
  19. else
  20. System.out.println(tmpR + " " + minR);
  21. break;
  22. }
  23. }
  24. }
先得到值后,再做后面的判断,多此一举,结果还超时了。

最后附上源码:

  1. import java.util.Scanner;
  2. public class Main {
  3. public static void main(String[] args) {
  4. Scanner sc = new Scanner(System.in);
  5. int n = sc.nextInt();
  6. while (n-- > 0) {
  7. int m = sc.nextInt();
  8. // findPrimesMinDistance(m);
  9. sqrtPrimesMinDistance1(m);
  10. }
  11. }
  12. public static boolean isPrimes(int m) {
  13. // 特殊值判断
  14. if (m == 0 || m == 1)
  15. return false;
  16. if (m == 2)
  17. return true;
  18. for (int i = 2; i <= Math.sqrt(m); i++) {
  19. if (m % i == 0)
  20. return false;
  21. }
  22. return true;
  23. }
  24. // 仿造讨论区的一模一样,318 923,本以为没有考虑到前后谁到谁小的情况就直接跳出了,后来发现很巧妙设计
  25. public static void sqrtPrimesMinDistance1(int m) {
  26. int tmpR, tmpL, minR, minL;
  27. minR = minL = 0;
  28. tmpR = tmpL = m;
  29. while (true) {
  30. if (isPrimes(tmpL)) {
  31. System.out.println(m - minL + " " + minL);
  32. break;
  33. }
  34. if (isPrimes(tmpR)) {
  35. System.out.println(m + minR + " " + minR);
  36. break;
  37. }
  38. tmpL--;
  39. tmpR++;
  40. minL++;
  41. minR++;
  42. }
  43. }
  44. // 通过存储范围内的素数表,直接取值,还超时。
  45. // 想一想也有可能,用素数表,就要算m+5(除0/1)次,用sqrt,算的是中间+左+右-->3*sqrt(m)次,
  46. // 演算了下,发现真的是sqrt计算量更小
  47. public static void findPrimesMinDistance(int m) {
  48. int[] primes = new int[m + 5];
  49. for (int i = 2; i < primes.length; i++) {
  50. if (primes[i] == 0)
  51. for (int k = 2; k * i < primes.length; k++) {
  52. primes[k * i] = 1; // 非质数都为1
  53. }
  54. }
  55. if (primes[m] == 0) // 本身是质数
  56. System.out.println(m + " 0");
  57. else {
  58. int minDistance = 0;
  59. int tmpR = m;
  60. // 向右找
  61. while (++tmpR < primes.length) {
  62. if (primes[tmpR] == 0) {
  63. minDistance = tmpR - m;
  64. break;
  65. }
  66. }
  67. // 向左找
  68. int tmpL = m;
  69. while (--tmpL > 0) {
  70. if (primes[tmpL] == 0) {
  71. if (m - tmpL <= minDistance) { // <=都是取到左边的
  72. minDistance = m - tmpL;
  73. } else
  74. tmpL = tmpR;
  75. break;
  76. }
  77. }
  78. System.out.println(tmpL + " " + minDistance);
  79. }
  80. }
  81. }






声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/75285
推荐阅读
相关标签
  

闽ICP备14008679号