【问题标题】:Finding all perfect squares of the form XXYY查找所有形如 XXYY 的完美正方形
【发布时间】:2011-01-09 13:05:14
【问题描述】:

我必须找到 XXYY 形式的 4 位数字,它们是任何整数的完全平方。我已经编写了这段代码,但是当我必须只过滤完美整数时,它会给出所有数字的平方根。

我只想在 sqrt(z) 为整数时显示它。

#include<math.h>
#include<iostream.h>
#include<conio.h>
void main()
{
 int x,y=4,z;
 clrscr();
 for(x=1;x<=9;x++)
 {
  z=11*(100*x+y);
  cout<<"\n"<<sqrt(z);

 }
 getch();
}

【问题讨论】:

  • 澄清一下,您要问的是“我如何测试 z 是平方数时?例如,我如何测试 sqrt(z) 是否返回整数结果?”
  • 你能举个例子吗?问题不清楚
  • 对于粗心的人:四位数的完美正方形的最后一位也是 44,因此XXYY 模式实际上简化为XX44。感谢史蒂夫·杰索普(Steve Jessop)向我指出:p
  • @Matthieu: 00 也是可能的(1600、2500 等)。
  • @dan04:对不起,我表达得不够准确。 XXYY 形式的正方形必须是 XX44 形式。还有其他 4 位数的方格,但它们的前两位数字互不相同。

标签: c++ algorithm


【解决方案1】:

我可能会这样检查,因为我的策略是对数学函数的准确性持偏执态度:

double root = sqrt(z);
int introot = floor(root + 0.5); // round to nearby integer
if ((introot * introot) == z) {  // integer arithmetic, so precise
    cout << introot << " == sqrt(" << z << ")\n";
}

double 可以准确地表示我们关心的所有整数(就此而言,在大多数实现中它可以准确地表示int 的所有值)。对于我们关心的所有整数,它还具有足够的精度来区分sqrt(x)sqrt(x+1)。 sqrt(10000) - sqrt(9999) 是 0.005,所以我们只需要 5 个小数位的精度来避免误报,因为非整数平方根不能比整数更接近。因此,一个好的 sqrt 实现可以足够准确,(int)root == root 本身就可以完成这项工作。

但是,该标准并未指定 sqrt 和其他数学函数的准确性。在 C99 中,这在 5.2.4.2.2/5 中明确说明:我不确定 C89 或 C++ 是否明确说明。所以我不愿意排除结果可能是 ulp 左右。如果sqrt(7744) 出现为 87.9999999999999-ish,int(root) == root 将给出假阴性

此外,sqrt 不能准确表示的数字要大得多(在 double 可以准确表示的限制附近)。所以我认为写额外的两行代码比写注释更容易解释为什么我认为数学函数在我关心的情况下是精确的:-)

【讨论】:

  • +1 明显的平方根检查是检查产生的平方
【解决方案2】:
#include <iostream>
int main(int argc, char** argv) {
    for (int i = 32; i < 100; ++i) { 
        // anything less than 32 or greater than 100 
        // doesn't result in a 4-digit number
        int s = i*i;
        if (s/100%11==0 && s%100%11==0) {
            std::cout << i << '\t' << s << std::endl;
        }
    }
}

http://ideone.com/1Bn77

【讨论】:

    【解决方案3】:

    我们可以注意到

    • 1 + 3 = 2^2
    • 1 + 3 + 5 = 3^2,
    • 1 + 3 + 5 + 7 = 4^2,

    sum(1 + 3 + ... (2N + 1)) 对于任何 N 都是正方形。 (很容易证明)

    现在我们可以生成[0000, 9999]中的所有方块,并检查每个方块是否为XXYY。

    【讨论】:

      【解决方案4】:

      完全没有需要在这个任务中涉及浮点数学。这是一段高效的代码,可以为您完成这项工作。

      由于您的数字必须是一个完美的正方形,因此只检查前面的完美正方形而不是所有四位数字会更快,过滤掉非正方形(就像您在第一次切割幼稚解决方案中所做的那样)。

      使用整数而不是浮点值也可能更安全,因为在进行平方根计算时不必担心所有这些不准确问题。

      #include <stdio.h>
      int main (void) {
          int d1, d2, d3, d4, sq, i = 32;
          while ((sq = i * i) <= 9999) {
              d1 = sq / 1000;
              d2 = (sq % 1000) / 100;
              d3 = (sq % 100) / 10;
              d4 = (sq % 10);
              if ((d1 == d2) && (d3 == d4))
                  printf ("   %d\n", i * i);
              i++;
          }
          return 0;
      }
      

      它依赖于第一个四位完美平方是32 * 321024(312 是 961)这一事实。因此它会检查 322、332、342 等等,直到超过四位数限制(即 1002 总共有 69 种可能性,而简单的解决方案将检查大约 9000 种可能性)。

      然后,对于每一种可能性,它都会检查您的最终XXYY 要求的数字,为您提供唯一答案:

      7744
      

      【讨论】:

      • “只检查前面的完美正方形而不是所有四位数字更快” - 他没有检查所有 4 位数字,但他只检查其中 9 个。对于这样一个小任务来说,速度并不是一个真正的问题,但我认为你正在将你的代码与稻草人进行比较。
      • @Steve:尽管问题和代码不一致,因为问题确实表明他想要所有这些。但是我不同意暴力解决方案是测试所有四位数:我们有一个模式,所以我们只需要检查其中的 90 个(1
      • @Matthieu:原发帖人使用了数学。如果一个平方数的最后两位小数相等,那么它们必然是44。所以问题和代码确实同意。也许不是很明显:我个人认为这个技巧值得评论:-)
      • @Steve:啊,如果已经说明会更容易:p 所以它是 9 平方根计算与 68 平方计算。我们的发帖人可能已经有最快的答案了:)
      • @Matthieu: (或00,但我们可以在这种情况下排除这种情况。aa00 不是任何数字 a 的正方形,因为aa 不是正方形任何数字a)。老实说,已经应用了这么多数学,根本不值得编写任何代码,只需在计算器上检查最后 9 个案例,然后将程序编写为 int main() { std::cout &lt;&lt; 7744 &lt;&lt; "\n"; } ;-)
      【解决方案5】:

      虽然我闻到了一个家庭作业问题,但这里有一些指导。 这个解决方案的问题是你取平方根,它引入了浮点运算和导致精确数学的问题。您可以通过以下方式接近:

      double epsilon = 0.00001;
      if ((z % 1.0) < epsilon || (z % 1.0) + epsilon > 1) {
          // it's probably an integer
      }
      

      可能值得你花时间重写这个算法,通过测试不断增加的数字的平方来检查数字是否符合该格式。您必须测试的最大数字是您正在寻找的最高完美平方的平方根。即 sqrt(9988) = 99.93... 所以无论如何你最多只需要测试 100 个数字。我认为您可能测试的最低数字是 1122,因此您实际上可以从 34 开始数。

      还有更好的解决方案,包括因式分解(以及模运算符的使用) 但我认为这些已经足够提示了。 ;-)

      【讨论】:

      • 我应该注意到我已经有一段时间没有使用 c++了,所以据我所知,sqrt 运算符可能(可能是)完美的正方形。
      • sqrt 的任何 合理 实现都将返回一个整数,用于 4 位完美平方。不过,我不认为该标准实际上指定了准确性,因此(a)大于您认为 sqrt 实现将永远存在的最不准确的容差并不是一个坏主意;并且(b)不要大到给出误报,我认为 0.00001 满足。
      • @marcog:对不起,你可以在 python 中做到这一点,而我在 c++ 中有点生疏。我的错。
      【解决方案6】:

      要检查sqrt(x) 是否为整数,请将其与其下限值进行比较:

      sqrt(x) == (int) sqrt(x)
      

      但是,由于精度问题,这实际上是比较浮点值的不好方法。您应该始终考虑一个小的错误组件:

      abs(sqrt(x) - ((int) sqrt(x))) < 0.0000001
      

      即使您进行了此更正,您的程序仍将输出sqrt(z),而您的目标是输出z。您还应该遍历所有 y 值,而不是只考虑 y=4(请注意,y 也是 0,与 x 不同)。

      【讨论】:

        【解决方案7】:

        I want to show the sqrt(z) only when it is integer.

        double result = sqrt( 25); // Took 25 as an example. Run this in a loop varying sqrt
                                   // parameter
        int checkResult = result;
        if ( checkResult == result )
            std::cout << "perfect Square" ;
        else
            std::cout << "not perfect square" ;
        

        【讨论】:

          【解决方案8】:

          你生成数字的方式是不正确 确实正确(我的错)所以你需要的只是找到平方的正确方法。 :)

          loop x: 1 to 9
            if(check_for_perfect_square(x*1100 + 44))
                   print: x*1100 + 44
          

          查看这里了解如何找到合适的正方形Perfect square and perfect cube

          【讨论】:

          • 其实是对的,他是在利用一个狡猾的事实,如果一个平方数的最后两位小数相等,那么它们一定是44
          【解决方案9】:

          您不需要取平方根。请注意,您可以轻松地按升序生成所有整数平方和所有数字 XXYY。所以你只需要遍历每个序列,寻找匹配项:

           int n = 0 ;
           int X = 1, Y = 0 ; // Set X=0 here to alow the solution 0000
           while (X < 10) {
             int nSquared = n * n ;
             int XXYY = 1100 * X + 11 * Y ;
          
             // Output them if they are equal
             if (nSquared == XXYY) cout << XXYY << endl ;
          
             // Increment the smaller of the two
             if (nSquared <= XXYY) n++ ;
             else if (Y < 9) Y++ ;
             else { Y = 0 ; X++ ; }
             }
          

          【讨论】:

            猜你喜欢
            • 2022-08-23
            • 1970-01-01
            • 2011-11-19
            • 1970-01-01
            • 1970-01-01
            • 2010-12-05
            • 2016-12-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多