【问题标题】:Minimal positive integer divisible by n能被 n 整除的最小正整数
【发布时间】:2014-05-30 14:13:06
【问题描述】:

对于给定的数字 n 找到可被 n 整除的最小正整数,并且数字之和等于 n。

我搜索了很多,也得到了这个问题的一些答案,但这些对我来说并不容易理解。我是一名新程序员,喜欢用 C 编程语言编写代码。这就是为什么如果有人帮助我在 C 中找到这个问题的解决方案,我会很高兴。 我如何尝试过,但我的代码不适用于 n 的大输入。这样 n = 999。 我的代码在这里:

#include <stdio.h>
#include <stdlib.h>
long long int summingDigit(long long int dividend);

int main()
{
    long long int n, dividend, add, ans;
    int i, test, c;
    scanf("%d", &test);
    for(c=1; c<=test; c++) {
    scanf("%lld", &n);
    for(i=1; ; i++) {
        dividend = n*i;
        add = summingDigit(dividend);
        if(add==n) {
            ans=dividend;
            break;
        }
    }
    printf("%lld\n", dividend);
    }
    return 0;
    }


long long int summingDigit(long long int dividend)
{
    long long int sum=0, rem;
    while(dividend!=0) {
        rem=dividend%10;
        dividend=dividend/10;
        sum=sum+rem;
    }
    return sum;
}

其实我希望得到这样的结果: 对于 n=1,结果=1 对于 n=10,结果=190 解释结果包含 3 位数字。它们的和 1+9+0 = 10 等于 n(10)。希望大家能够理解。

请给我一个更好的方法来节省这个问题的时间。因为我的解决方案将花费太多时间。但我无法理解其他编程语言。因此,请用 C 轻松解释这一点。感谢您帮助我进阶。

我找到了解决方案,但不明白。如果您有足够的时间,请让我了解完整的程序。

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define F first
#define S second
#define N 1100
#define mp make_pair
queue<pair<int, int> >Q;
short sumTrace[N][N], mulTrace[N][N];

void print(int sum, int mul)
{
    if (sumTrace[sum][mul] == 42)return;
    print(sum-sumTrace[sum][mul], mulTrace[sum][mul]);
    printf("%d",sumTrace[sum][mul]);
}
void solve(int n)
{
    Q.push(mp(0,0));
    sumTrace[0][0]=42; // any number greater than 9
    while (1)
    {
        int sum = Q.front().F;
        int mul = Q.front().S;
        if (sum == n && mul == 0) break;
        Q.pop();
        for (int i=0; i<10; i++)
        {
            int nsum = sum+i;
            if (nsum > n)break;
            int nmul = (mul*10+i)%n;
            if (sumTrace[nsum][nmul] == -1)
            {
                Q.push(mp(nsum, nmul));
                sumTrace[nsum][nmul] = i;
                mulTrace[nsum][nmul] = mul;
            }
        }
    }
    print(n,0);
    while(!Q.empty())Q.pop();
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        scanf("%d", &n);
        memset(sumTrace, -1, sizeof sumTrace);
        solve(n);
        printf("\n");
    }
    return 0;
}

【问题讨论】:

  • 很可能对于大的n,你会从dividend = n * i 得到溢出。有时long long 不够长。
  • 那我该如何优化呢?可能是字符串会在这方面有所帮助。但我无法实现这种想法。如果有人可以优化此代码,我可能已经学到了新知识。所以,请尝试为我优化这段代码。
  • n 的大值使用这种方法将需要使用比使用字符串快得多的大整数库。就个人而言,我认为解决这个问题可能有一条捷径(我认为这是你所追求的)......这个问题来自 Project Euler。
  • 还有另一个资源:oeis.org/A002998

标签: c algorithm math


【解决方案1】:

一个小的可能优化如下:

你可以在这里使用一点数学。

如果存在i,使得n*i的位数和为n,则:

Say n*i = p + 10q + 100r + 1000s +... (where p, q, r, s are digits of n*i)
Then p + q + r + s ... = n.

Hence n * (i-1) = 9q + 99r + 999s +... (after subtracting n from both sides)
                = 9 * (q + 11r + 111s +... )

因此您注意到 n*(i-1) 应始终是 9 的倍数

因此,如果 n 最初不是 9 的倍数,那么您可以通过采用 9 (i += 9) 而不是 1 (i++) 的步长来跳过许多可能的候选。

你可以在这些方面思考,你可能会想出更好的东西。

【讨论】:

  • 感谢您的考虑。显然,我们将跳过许多步骤,以降低时间复杂度。但我无法实现这一点。请用你的逻辑优化我的代码。并给出一个完整的代码,以便代码在编译器中运行,因为我不是高级程序员:(
  • stackoverflow 不是来帮你编程的……只是为了帮助你
  • 是的,克里斯·梅斯。这比源代码更能解决问题。
【解决方案2】:

这样的? ;oP

m=n+1; while (summingDigit(m)!=n && m%n!=0) m++;

或者就像你做的那样。

m=2*n; while (summingDigit(m)!=n) m+=n;

【讨论】:

  • 这是什么意思?我无法理解。请解释。你了解这个问题/问题的要求吗?
  • 我只是挪用你的代码来理解这个问题,首先我用 while 循环替换无限 for loop 和 break 条件.
  • summingDigit(long long int divide)函数的作用是计算被除数位数的总和。哪个股息也等于n。再举一个例子,如果输入为 12,输出将为 48。输出 4+8 = 12 的数字之和等于 n (12)。
  • 好的,我明白了。但我的问题是,如果 n 为 1000 会怎样。输出将是一个很大的数字!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
  • 1970-01-01
  • 2016-03-20
  • 2022-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多