【问题标题】:Find two integers such that their product is close to a given real找到两个整数,使得它们的乘积接近给定的实数
【发布时间】:2012-10-25 06:41:42
【问题描述】:

我正在寻找一种算法来找到两个整数值x,y,以便它们的乘积尽可能接近给定的双精度值k,而它们的差异很小。

示例:矩形的面积是k=21.5,我想找到该矩形的边长,约束条件是它们必须是整数,在这种情况下,一些可能的解决方案是(不包括排列)(x=4,y=5),(x=3,y=7) 和愚蠢的解决方案(x=21,y=1)

事实上,(3,7) 夫妇和(21,1) 夫妇有相同的区别

21.5-3*7=0.5 = 21.5-21*1

对于(4,5) 夫妇 21.5-4*5=1.5

但是(4,5)这对夫妇更可取,因为他们的区别是1,所以矩形“更平方”。

有没有一种方法可以提取那些x,y 值的差异最小并且它们的乘积与 k 的差异也最小的方法?

【问题讨论】:

  • 对于 33,你想要 3*11、5*6 还是 6*6?
  • 取平方根并上下四舍五入怎么样?
  • 由于4,53,7 更可取,尽管距离21.5 更远,所以您优先考虑最小化|x-y| 而不是最小化|x*y - k|。所以最好的答案是x == y。那么剩下要解决的唯一问题是哪个平方数最接近k。正如尼莫所说,它将是k 平方根的天花板或地板的平方。我怀疑实际上矩形“更方形”而不是“更准确”的重要性是有限度的,但你还没有描述你想如何解决两者之间的紧张关系。
  • @Lundin:他不能开始舍入或截断 k。如果 k 为 21.5,他事先并不知道 xy = 21 还是 xy = 22 会给出更好的解。如果他选错了,他会得到错误的答案。
  • 您的问题没有明确定义。在找到乘积最接近 p 的 2 个整数 x,y 时,需要记住两个因素:我们必须考虑 x-y 和 p-xy。也许你可以想出一个公式之类的东西,假设 x,y 的质量是这样计算的: f(pxy)+g(xy) 其中 f,g 是两个函数 -> 那么你的问题将被很好地定义。

标签: c++ c algorithm integer


【解决方案1】:

你想最小化

  1. 因素XY的区别
  2. 产品X × YP的区别。

您提供了一个示例,其中这些目标相互矛盾3 × 74 × 5 更接近 21,但后者的因素更方。因此,不可能有任何算法同时最小化两者。

你可以将这两个目标加权并合二为一,然后通过non-linear integer programming解决问题:

       min c × |X × Y - P|  +  d × |X – Y|
subject to X, Y ∈ ℤ
           X, Y ≥ 0

其中 c, d 是非负数,用于定义您对哪个目标的重视程度。

【讨论】:

    【解决方案2】:
    1. 让给定的 double 为 K。

    2. 取K的楼层,让它成为F。

    3. 取 2 个大小为 F*F 的整数数组。让他们成为Ar1,Ar2。

    4. 像这样运行循环

      int z = 0 ;
      
      for ( int i = 1 ; i <= F ; ++i )
      {
         for ( int j = 1 ; j <= F ; ++j )           
         {
             Ar1[z] = i * j ;
             Ar2[z] = i - j ; 
             ++ z ;            
         }
      }
      

    您现在得到了所有可能数字的差异/产品对。现在为接近值 K 的产品分配一些“优先级值”,而将其他一些分配给较小的差异。现在从 0 到 F*F 遍历这些数组,并通过检查条件找到所需的对。

    例如。让接近 K 的优先级为 1,而差异较小的优先级为 0.5。考虑另一个大小为 F*F 的数组 Ar3。那么,

        for ( int i = 0 ; i <= F*F ; ++i )
        {
           Ar3[i] = (Ar1[i] - K)* 1 + (Ar2[i] * .5) ; 
        }
    

    遍历 Ar3 以找到最大值,这将是您要查找的对。

    【讨论】:

      【解决方案3】:
      double best = DBL_MAX;
      int a, b;
      for (int i = 1; i <= sqrt(k); i++)
      {
          int j = round(k/i);
          double d = abs(k - i*j);
          if (d < best)
          {
              best = d;
              a = i;
              b = j;
          }
      }
      

      【讨论】:

      • 在代码中添加一些解释将有助于这个答案
      【解决方案4】:

      取平方根,取一个整数,取另一个整数。

      #include <iostream>
      #include <cmath>
      
      int main(){
          double real_value = 21.5;
          int sign = real_value > 0 ? 1 : -1; 
          int x = std::floor(std::sqrt(std::abs(real_value)));
          int y = std::ceil(std::sqrt(std::abs(real_value)));
          x *= sign;
      
          std::cout << x << "*" << y << "=" << (x*y) << " ~~ " << real_value << "\n";
          return 0;
      }
      

      请注意,这种方法只会使您在xy 之间保持良好的距离,例如如果real_value = 10 然后x=3y=4,但产品是12。如果您想在产品和实际值之间获得更好的距离,您必须调整整数并增加它们的差异。

      【讨论】:

      • 尝试 18.888 的解决方案。正确的输出显然是 19 * 1
      【解决方案5】:

      您必须查看相关数字的平方根。对于 21.5 sqrt(21.5) = 4.6368,实际上你找到的数字就在这个值附近。

      【讨论】:

      • 2,991 怎么样? 3 x 997 正好是 2,991,没有其他方法可以得到。 3 和 997 离平方根很远,这会给你 54*55 即 2,970。
      • 或者甚至尝试 18.888 答案是 19*1,你的方法永远找不到它。
      • @DavidSchwartz 这是真的,但请参阅 Steve Jessop 对关于最小化 |x-y| 优先于最小化 |x*y - k| 的原始问题的评论。这似乎表明正确答案 3 x 997 不太理想。
      • 我认为这个问题试图表明让产品尽可能接近是重中之重。最方形的形状是第二优先级。我同意这不清楚,但我认为这是最合理的解读。
      • @DavidSchwartz:如果它试图表明这是最重要的,那么它就会失败。在给出的唯一示例 (k = 21.5) 中,该问题明确表示答案 (4,5) 优于 (3,7)。但对于 (5,5) 是否会因为更方正而更受青睐的问题却保持沉默。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-03
      相关资源
      最近更新 更多