【问题标题】:Find three numbers that are divisors of given number and their sum is minimal找出三个数是给定数的除数且它们的和最小
【发布时间】:2019-11-16 14:11:03
【问题描述】:

我试图解决这个问题超过一天,但我无法找到合理的解决方案。我认为这是一个相当简单的编程问题,更像是一个算法问题。我们有一个给定的数字 N, (1

附:一些例子 - 100 = 4×5×5, 121 = 11×11×1, 8 = 2×2×2, 400 = 8×5×10, 1000 = 10×10×10,4000=16×10×25等等。

int main() {
    int m = 0, n = 0, p = 0, q = 0, i = 0;;
    std::cin >> n;
    i = int(std::cbrt(n));
    while (true) {
        int ten = std::cbrt(n);
        if (pow(ten, 3) == n) {
            m = ten;
            p = ten;
            q = ten;
            break;
        }
        int square = n;
        if (i * i == square) {
            n = i;
            m = i;
            p = i;
            break;
        }
        if (i == 1) {
            m = n;
            p = 1;
            q = 1;
            break;
        }
        if (n % i == 0) {
            n = n / i;
            m = i;
            p = n;
            break;
        }
        i++;
    }
    i = std::cbrt(n);
    while (true) {
        int ten = std::cbrt(n);
        if (pow(ten, 3) == n) {
            m = ten;
            p = ten;
            q = ten;
            break;
        }
        int square = n;
        if (i * i == square) {
            p = i;
            q = i;
            break;
        }
        if (i == 1) {
            q = 1;
            break;
        }
        if (n % i == 0) {
            q = n / i;
            p = i;
            break;
        }
        i++;
    }
    std::cout << m << " " << p << " " << q << std::endl;
    return 0;
}

【问题讨论】:

  • 请扩展“不起作用”。如果没有输入、预期输出和实际输出的具体示例,我选择假设“不工作”意味着您的计算机关闭,因为这符合字面意思。一旦你选择了一个有问题的案例,看看你是否可以减少我们被要求检查的代码量。 minimal reproducible example 是调试中有用的第一步。
  • 好吧,“不工作”意味着它输出错误的答案。
  • 为什么我两次看到几乎相同的代码?
  • 我认为随着数量的增加,反复试验会变得乏味。如何分解它并构造绝对值接近的因子?作为奖励,尝试击败 1 + -1 + -N。
  • @Stuffy 更好,但还不够。错误的答案到底是什么?正如我所说,您应该给出输入、预期输出和实际输出的具体示例。 (你说6N 的一个值,但它不起作用。那是你的输入。所以你所缺少的只是一句话,比如:“当N 是6 时,我应该得到3,2,1,但我实际上得到了6,1,1。” 或者不管数字是什么——我承认 6 小到足以让我猜到它们。)

标签: c++ algorithm


【解决方案1】:

我发现你的想法很有趣。首先寻找一个接近三次根的分频器。然后,在第二步中,寻找接近剩余平方根的除法器。

以下代码似乎适用于您引用的案例,包括 6 的输入。

我主要尝试简化您的代码,删除看起来很奇怪且似乎没有用的代码。我还确保第二步是有效地尝试搜索接近剩余平方根的因子,这有一点错误。

我没有尝试提高程序的速度。我想第一步是测试算法的有效性。在第二步中,正如评论中所建议的那样,可以使用输入的主要因素来固定程序,同时保持相同的策略。

在这里,最坏情况下的复杂度为 O(n),这看起来已经相当不错了。

编辑: 为了稍微固定程序,我尝试以负序循环(i-- 而不是i++)。我检查了你提出的测试没有区别。但是,对于我执行的另一项测试,我获得了收益...

对于n = 124267948,我现在获得(316, 56179, 7) sum = 56502 而不是(553, 4, 56179) sum = 56736

这意味着在验证算法之前确实需要进行一些进一步的测试和分析。

**编辑2:** 我在 1 和 1e6 之间对n 进行了系统测试,并比较了两个变体(i++ 和 i--)。它们通常提供相同的结果,在其他地方其中一个或另一个更好。需要进一步调查。

编辑 3: 我做了一个系统的比较,一个最优方案考虑了第一个除法器 (m) 的所有可能值,然后在余数的 sqrt (n/m) 附近寻找一个除法器。我知道这个最优方案通常比其他两个更好。例如n=44。这种最优方案更复杂,但计算时间似乎相当短。

#include    <iostream>
#include    <cmath>

int main() {
int m = 0, n = 0, p = 0, q = 0, i;
bool end = false;
std::cin >> n;
i = int(std::cbrt(n));
//std::cout << "cbrt(n) = " << i << "\n";

if (n == 1) {
    m = p = q = 1;
    end = true;
} else {
    if (i == 1) i = 2;
    if (pow(i, 3) == n) {
         m = i;
         p = i;
         q = i;
         end = true;    
    }
}

if (!end) {

//  1st step: research of a factor almost equal to a cubic root
    i++;
    while (true) {
        if (n % i == 0) {
            n = n / i;
            m = i;
            break;
        }
        i--;
    }

 // 2nd step: research of factor almost equal to the sqrt 
    i = std::sqrt(n) + 1;

    //std::cout << "before square search: n = " << n  << "\ti = " << i << "\n";
    while (!end) {  
        if (n % i == 0) {
            p = i;
            q = n/i;
            end = true;
        }
        i--;
    }
}

    std::cout << m << " " << p << " " << q << std::endl;
    return 0;
}

【讨论】:

  • 我猜你已经阅读了编辑。我纠正了你的程序,但并没有真正改变算法。现在需要一些进一步的系统测试来验证算法本身。
猜你喜欢
  • 1970-01-01
  • 2014-11-08
  • 2020-01-01
  • 1970-01-01
  • 2012-03-18
  • 2021-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多