蓝桥杯 四平方和

 

题目:四平方和

 

看到这个题目,第一个思路就是:

  枚举abcd的值,然后判断它们的平方和是不是等于N。

我们可以分析一下abcd的枚举范围

  a : 0 ~ sqrt( 5000000 / 4 )

  b : 0 ~ sqrt( 5000000 / 3 )

  c : 0 ~ sqrt( 5000000 / 2 )

  d : 0 ~ sqrt( 5000000 )

  这样abcd的需要枚举的范围大约都是1000~2000,总枚举量是1012这个量级。而108这个量级的计算量大约用时1秒。所以1012这个计算量肯定会超时

 

 

 

超时我们就要想办法优化。最先能想到一个优化的办法——减少枚举的变量。

思路2:

  枚举a、b、c,然后判断 N - a- b- c是不是完全平方数。

同理,先分析一下abc的枚举范围:

  a : 0 ~ sqrt( 5000000 / 4 )

  b : 0 ~ sqrt( 5000000 / 3 )

  c : 0 ~ sqrt( 5000000 / 2 )

  可以发现abc的枚举范围仍然是1000~2000之间,总的枚举量大概在109量级。再加上判断一个整数X是不是完全平方数(开根号取整得到Y,然后再判断Y*Y是不是等于X即可)复杂度是O(1)。所以整个算法的复杂度是O(N1.5),还是会超时

 

 

 

还超时,说明我们还要继续优化。

思路3:

  只枚举a、b,把余下的部分记作R,即 R = N - a- b2

于是我们的问题变成:c+ d= R 有没有解?如果有解,其中c最小的解是什么?由于题目要求是abcd联合主键升序第一的解。所以这里要快速求出来c最小的解。比如这时R = 25,那么得到的解应该是 c = 0, d = 5,而不是 c = 3,d = 4。这里哈希表就派上用场了。我们可以预先求出来 R = c+ d的解,用 unordered_map<int, int> f 来保存一个R对应的c。比如f[5]=1,表示R=5的解是 c = 1,(d=2可以由R和c算出来)。我们可以求出f[0], f[1], … f[5000000]的值,通过查哈希表用O(1)复杂度找到R = c+ d的解,这样就更进一步优化了。

 

代码如下:

 1 #include <cmath>
 2 #include <iostream>
 3 #include <unordered_map>
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     int n;
 9     unordered_map<int, int> f;
10     
11     cin >> n;
12     //预处理,求取 R = c2 + d2 的解并保存在unordered_map
13     for(int c = 0; c * c * 2 <= n; c ++ )
14         for(int d = c; c * c + d * d <= n; d ++)
15             if(f.find( c * c + d * d ) == f.end())    //在f中不存在则保存
16                 f[c * c + d * d] = c;
17     
18     for(int a = 0; a * a * 4 <= n; a ++)
19         for(int b = a; a * a + b * b <= n / 2; a ++)
20             if(f.find(n - a * a - b * b) != f.end())    //查哈希表,有解的话,计算并输出 
21             {
22                 int c = f[n - a * a - b * b];
23                 int d = int(sqrt(n - a * a - b * b - c * c) + 1e-3);
24                 cout << a << ' ' << b << ' ' << c << ' ' << d << endl;
25                 return 0;
26             }
27     
28     return 0;
29 } 
 
注:代码中 1e-3 的作用:
  sqrt的返回值是浮点数,会有精度误差。结果有可能出现比实际值略小的情况,比如sqrt(25)=4.999999999。而int强制类型转换是向下取整,int(4.9999999999)=4。这样就会由于精度误差误判25不是完全平方数。所以我给sqrt的结果加上了一个很小的浮点数,1e-3, 1e-6都可以,为了是把4.9999999这样的数变成5.00099999 这样int取整之后仍然是5。当然也可以不加。
 
 
 

posted on 2018-06-12 20:00  Tuple  阅读(1726)  评论(1编辑  收藏  举报

导航