多重循环优化

喜欢ヅ旅行 2022-07-28 04:13 245阅读 0赞

四平方和 (程序设计)
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

这道题,我当时就是写了一个四重循环遍历搜索,也跑了最大的一组样例,没有超时,就直接交了!后来,在网上发现,这样做好像是超时的。唉,还是自己做题做的少,算法研究的少啊!要是想在任何一门比赛中得到好成绩,还是需要算法过硬才行啊!

  1. //1.四重循环直撸
  2. import java.util.Scanner;
  3. public class Main {
  4. public static int N = 0;
  5. public static void Op(){
  6. for(int a=0;a*a<N;a++){
  7. for(int b=0;b*b<N;b++){
  8. for(int c=0;c*c<N;c++){
  9. for(int d=0;d*d<N;d++){
  10. if(a*a+b*b+c*c+d*d==N){
  11. System.out.println(a+" "+b+" "+c+" "+d);
  12. return ;
  13. }
  14. }
  15. }
  16. }
  17. }
  18. }
  19. public static void main(String[] args) {
  20. // TODO Auto-generated method stub
  21. Scanner in = new Scanner(System.in);
  22. while(in.hasNext()){
  23. N = in.nextInt();
  24. //long t1 = System.currentTimeMillis();
  25. Op();
  26. //long t2 = System.currentTimeMillis();
  27. //System.out.println("Time cost:"+(t2-t1));
  28. }
  29. }
  30. }

上面这个代码,虽然我试了几次都没有超时,最大的耗时是2800ms,可是毕竟是4重循环,虽然实际为O(n^2),但是参考了书上的代码进行如下优化:

  1. //枚举+二分搜索优化
  2. import java.util.Arrays;
  3. import java.util.Random;
  4. import java.util.Scanner;
  5. public class Main {
  6. public static int n, line;
  7. public static int[] arr;
  8. public static void find(){
  9. arr = new int[line];
  10. for(int i=0;i<line;i++) arr[i] = i * i;
  11. for(int a=0;a<line;a++){
  12. for(int b=0;b<line;b++){
  13. for(int c=0;c<line;c++){
  14. int t = n - arr[a] - arr[b] - arr[c];
  15. int index = -1;
  16. index = Arrays.binarySearch(arr, t);
  17. if(index>=0){
  18. // System.out.println("n:"+n);
  19. System.out.println(a+" "+b+" "+c+" "+(int)Math.sqrt(t));
  20. return ;
  21. }
  22. }
  23. }
  24. }
  25. }
  26. public static void main(String[] args) {
  27. // TODO Auto-generated method stub
  28. Scanner in = new Scanner(System.in);
  29. // Random rand = new Random();
  30. for(int i=0;i<10000;i++){
  31. //n = rand.nextInt(5000000);
  32. n = in.nextInt();
  33. long t1 = System.currentTimeMillis();
  34. line = (int)Math.sqrt(n)+10;
  35. find();
  36. long t2 = System.currentTimeMillis();
  37. // System.out.println("Time cost:"+(t2-t1));
  38. // if(t2-t1>3000){
  39. // System.out.println("breakpoint!");
  40. // break;
  41. // }
  42. }
  43. }
  44. }

优化后的算法复杂度从O(n^4)变为O(n^3*log n),原理是这样的,既然是求 a^2 + b^2 + c^2 + d^2 = N,先枚举出[0,sqrt(N)+10](加上10是为了保险)所有值的平方,并将其存在arr数组中(arr[i] = i * i),然后问题就变成了“在数组arr中是否存有四个数A,B,C,D使得A+B+C+D=N”,将等式变形D=N-A-B-C,就是等价于在数组arr中寻找有没有t=N-A-B-C这样一个值,由于数组arr是升序的,可以直接使用二分查找,其复杂度为log n,再加上外围的三层循环,总复杂度为O(n^3*log n)。

发表评论

表情:
评论列表 (有 0 条评论,245人围观)

还没有评论,来说两句吧...

相关阅读

    相关 多重循环优化

    > 四平方和 (程序设计) > 四平方和定理,又称为拉格朗日定理: > 每个正整数都可以表示为至多4个正整数的平方和。 > 如果把0包括进去,就正好可以表示为4个数

    相关 java 如何跳出多重循环

    跳出多重循环有两种方法 (一)可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环 例: out:for(

    相关 go 多重循环控制

    一 基本介绍 1 将一个循环放在另一个循环体内,就形成了嵌套循环。在外边的 for 称为外层循环,在里面的 for 循环称为内层循环。建议:一般使用两层,最多不要超过三层