【问题标题】:Breaking a number into the sum of two numbers将一个数分解为两个数之和
【发布时间】:2020-01-16 20:40:34
【问题描述】:

我对这样的任务有疑问:

编写一个程序,找出这样一对数字 x 和 y,它们的和等于 n。此外,这对数字还应满足以下条件:

  • 数字 x 至少有 2 位,
  • 数字 y 比数字 x 少一位。

N 来自

对于数字 80,输出应如下所示:

79 + 1 = 80
78 + 2 = 80
77 + 3 = 80
76 + 4 = 80
75 + 5 = 80
74 + 6 = 80
73 + 7 = 80
72 + 8 = 80
71 + 9 = 80

我编写了一个在大多数情况下都有效的代码,但是在测试数字 100000 时系统拒绝了解决方案,因为程序没有找到这样的对 - 测试需要 9000 个这样的对。我不明白出了什么问题,因为我认为该程序还可以。我想请教一些建议。

我的代码:

#include <stdio.h>
#include <math.h>

int digit_count(int n)
{
    int i = 0;
    while (n > 0)
    {
        n /= 10;
        i++;
    }
    return i;
}

int breakdown(int n)
{
    long n_digits = digit_count(n), check = 0, count = 1;
    long double y_max = pow(10, (n_digits - 1)) - 1, y_min = (pow(10, (n_digits - 2)));

    for (int i = (int)y_min; i <= (int)y_max; i++)
    {
        if (digit_count(n - i) >= 2 && digit_count(i)+1 == digit_count(n - 1))
        {
            printf("%d + %d = %d          %d\n", n - i, i, n, count);
            check = 1;
            count++;
        }
    }

    if (check == 0)
    {
        printf("Nothing to show.");
    }
    return 0;
}

int main(void)
{
    unsigned int n = 0;
    printf("Podaj N: ");
    if (1 != scanf("%u", &n))
    {
        printf("Incorrect input");
        return 1;
    }
    if (n > 1000000 || n < 10)
    {
        printf("Incorrect input");
        return 1;
    }

    breakdown(n);
    return 0;
}

PS:我忘了说 count 变量在这里只是为了调试

【问题讨论】:

  • digit_count(n-1) 应该是digit_count(n-i) ?
  • 我建议阅读this article 了解调试代码的技术。您应该手动找到一对符合所有条件且总和为 100000 的数字 xy。然后您可以调试您的代码以找出它无法找到该对的原因。
  • long double y_max = pow(10, (n_digits - 1)) - 1, 你的代码不需要双打。我认为在这种情况下,它们会使您的代码变慢。只需编写您自己的小int pow10_int(int) 函数。 for (int i = (int)y_min; i &lt;= (int)y_max; i++) 将运行 很多 次。 y_maxy_min 的值应该是多少?他们是否以某种方式被选中?为什么你从n_digits - 2而不是n_digits / 2开始? the system rejects the solution - “系统”拒绝解决方案,因为没有返回足够的对? digit_count(n - i) &gt;= 2 你就不能n - i &gt;= 10吗?
  • 我认为这个程序是这样工作的:digit_count(First number) == digit_count(number) == digit_count (second_number)+1
  • 不,不要将更正后的代码放在问题中!编写一个答案,说明代码中的问题以及您如何解决它。当您解决自己的问题时,我们鼓励您自行回答(您也可以获得对答案的投票)。

标签: c


【解决方案1】:

我以这种方式解决了这个问题。现在它适用于根据任务范围内的所有数字。

#include <stdio.h>
#include <math.h>

int digit_count(int n)
{
    int i = 0;
    while (n > 0)
    {
        n /= 10;
        i++;
    }
    return i;
}

int breakdown(int n)
{
    int n_digits = digit_count(n), check = 0;
    double y_max = pow(10, n_digits - 1) - 1; 
    //int i = 0 instead of i = y_min = (pow(10, (n_digits - 2))
    for (int i = 0; i <= (int)y_max; i++)
    {
        //instead of if (digit_count(n - i) >= 2 && digit_count(i)+1 == digit_count(n - i))
        if (digit_count(n - i) >= 2 && digit_count(n - i) == digit_count(i) + 1) 
        {
            printf("%d + %d = %d\n", n - i, i, n);
            check = 1;
        }
    }

    if (check == 0)
    {
        printf("Nothing to show.");
    }
    return 0;
}

int main(void)
{
    unsigned int n = 0;
    printf("Podaj N: ");
    if (1 != scanf("%u", &n))
    {
        printf("Incorrect input");
        return 1;
    }
    if (n > 1000000 || n < 10)
    {
        printf("Incorrect input");
        return 1;
    }

    breakdown(n);
    return 0;
}

【讨论】:

    【解决方案2】:

    发布的代码检查 所有 [10k - 2, 10k - 1 - 1] 中的数字,k 是数字n 的位数,使用扩展(和错误)条件

    if (digit_count(n - i) >= 2 && digit_count(i)+1 == digit_count(n - 1)) { /* ... */ }
    //                                                                 ^
    

    您可以通过仔细计算xy 值范围的有效范围来解决所有(或至少大部分)这些数字计数的问题。

    下面是一个可能的实现

    #include <assert.h>
    #include <stdbool.h>
    #include <stdio.h>
    
    static inline long min_(long a, long b)
    {
        return b < a ? b : a;   
    }
    
    static inline long max_(long a, long b)
    {
        return b < a ? a : b;   
    }
    
    int digit_count(long n);
    
    // Specilization for integer exponent. 
    long pow_10_(int exponent);
    
    // A little helper struct
    typedef struct range_s
    {
        long begin, end;
    } range_t;
    
    // Shrinks the range of the y values so that all the x = z - y are valid
    // (the right nummber of digits and less than z).
    range_t find_range(long z, long x_0)
    {
        range_t y = {max_(1, x_0 / 10), x_0};
        range_t x = {x_0, min_(z, x_0 * 10)};
    
        long x_1 = z - y.begin;
        if (x_1 < x.begin)
            y.end = y.begin;
        else if (x_1 >= x.end)
            y.begin = min_(z - x.end + 1, y.end);
    
        long x_2 = z - y.end;
        if (x_2 > x.end)
            y.begin = y.end;
        else if (x_2 <= x.begin)
            y.end = max_(z - x.begin + 1, y.begin);
    
        return y;
    }
    
    long print_sums(long z, range_t y);
    
    long breakdown(long z)
    {
        int n_digits = digit_count(z); // <- Only once.
    
        long x_0 = pow_10_(n_digits - 1);
    
        // Depending on z, the x values may have the same number of digits of z or
        // one less. 
        long count = 0;
        if (n_digits > 2)
        {
            count += print_sums(z, find_range(z, x_0 / 10));
        }
        count += print_sums(z, find_range(z, x_0));
        return count;
    }
    
    int main(void)
    {
        long n = 0;
        if (1 != scanf("%lu", &n))
        {
            printf("Incorrect input");
            return 1;
        }
        if (n > 1000000 || n < 10)
        {
            printf("Incorrect input");
            return 1;
        }
    
        printf("\nCount: %ld\n", breakdown(n));
        return 0;
    }
    
    int digit_count(long n)
    {
        int i = 0;
        while (n > 0)
        {
            n /= 10;
            i++;
        }
        return i ? i : 1;  // I consider 0 a 1-digit number.
    }
    
    long pow_10_(int exponent)
    {
        if (exponent < 0)
            return 0;
        long result = 1;
        while (exponent-- > 0)
            result *= 10;
        return result;
    }
    
    #define SAMPLES 5
    
    long print_sums(long z, range_t y)
    {
        for (long i = y.begin; i < y.end; ++i)
    #ifndef SHOW_ONLY_SAMPLES
            printf("%ld + %ld = %ld\n", z - i, i, z);
    #else
            if ( i < y.begin + SAMPLES - 1 || i > y.end - SAMPLES )
                printf("%ld + %ld = %ld\n", z - i, i, z);
            else if ( i == y.begin + SAMPLES )
                puts("...");
    #endif
        return  y.end - y.begin;  
    }
    

    可测试here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-01
      相关资源
      最近更新 更多