【问题标题】:Find the minimum number of steps to decrease N to zero找到将 N 减小到零的最小步数
【发布时间】:2019-04-27 12:51:47
【问题描述】:

最近几天在尝试完成以下任务时遇到了一些困难,希望大家能提供帮助:

我得到一个单一的数字 N,我可以在每次移动中对 N 执行两个操作中的任何一个:

- 如果我们取 2 个整数,其中 N = x * y ,那么我们可以将 N 的值更改为 x 和 y 之间的最大值。

- 将 N 的值减 1。

我想找到将 N 减少到零的最小步数。 这是我到目前为止所拥有的,我不确定实现查找除数 (someFindDevisorFunction) 的函数的最佳方法是什么,以及这个 'f' 函数是否真的会产生所需的输出.

  int f(int n)
{
  int div,firstWay,secondWay;
  if(n == 0)
    return 0;

  div = SomefindDivisorFunction(n);
  firstWay = 1 + f(n-1);
  if(div != 1)
  {
    secondWay = 1 + f(div);
    if (firstWay < secondWay)
        return firstWay;
    return secondWay;
  }

  return firstWay;
}

例如,如果我输入数字 150 ,输出将是: 75 - 25 - 5 - 4 - 2 - 1 - 0

【问题讨论】:

  • 我不明白:对于 150 我会说:150=15*10 => 15. 15=5*3=> 5, ...,这比您的建议少了一步解决方案。
  • 我不明白为什么你的输出有 75 作为 150 的第一步。为什么不是 15,因为 150 = 15 * 10 和 15 = max(15, 10)?在我看来,通过选择 a 和 b 作为最接近 sqrt(N) 的整数辅因子,您可以最快地收敛到零。
  • 您的问题是什么?与您展示的简单蛮力不同的方法? SomefindDivisorFunction() 的代码?请更具体。如果是函数的代码,那么请考虑将您的问题集中在该部分上,
  • 你忘了一个问题吗?例如,关于 a 和 b 是否互质?否则,如这里建议的那样,您应该考虑它,以便这两个因素尽可能接近 sqrt(N)。
  • 正如问题中所述,对于任何正 N,我们有 N → -1(因为 N = -1•-N 和 -1 = max(-1, -N)) → -2(递减)→ 2(因为 -2 = -1•2)→ 1(递减)→ 0(递减)。

标签: c recursion minimum


【解决方案1】:

我认为这是一个递归或迭代问题。

OP 的方法暗示递归。


递归解决方案如下:

在每一步,代码都会计算各种备选方案的步数:

steps(n) = min(
  steps(factor1_of_n) + 1,
  steps(factor2_of_n) + 1,
  steps(factor3_of_n) + 1,
  ...
  steps(n-1) + 1)

下面的编码解决方案效率低下,但它确实探索了所有可能性并找到了答案。

int solve_helper(int n, bool print) {
  int best_quot = 0;
  int best_quot_score = INT_MAX;
  int quot;
  for (int p = 2; p <= (quot = n / p); p++) {
    int rem = n % p;
    if (rem == 0 && quot > 1) {
      int score = solve_helper(quot, false) + 1;
      if (score < best_quot_score) {
        best_quot_score = score;
        best_quot = quot;
      }
    }
  }

  int dec_score = n > 0 ? solve_helper(n - 1, false) + 1 : 0;

  if (best_quot_score < dec_score) {
    if (print) {
      printf("/ %d ", best_quot);
      solve_helper(best_quot, true);
    }
    return best_quot_score;
  }
  if (print && n > 0) {
    printf("- %d ", n - 1);
    solve_helper(n - 1, true);
  }
  return dec_score;
}

int main() {
  int n = 75;
  printf("%d ", n);
  solve(n, true);
  printf("\n");
}

输出

75 / 25 / 5 - 4 / 2 - 1 - 0 

迭代

待定

【讨论】:

  • 谢谢你的回答,我到家后测试一下。但是,我想尝试以递归方式找到更有效的方法。
  • 记得先让它正常运行,然后再提高效率。很容易加快速度,但无法得出最佳解决方案。
【解决方案2】:

如果您开始寻找 2 的除数,然后逐步向上,那么您找到的最后一对除数将包括最大的除数。或者,您可以从除数 = N/2 开始搜索并向下计算,当找到的第一个除数将是 N 的最大除数时。

【讨论】:

  • 确实,以或或向下的方式工作会找到最大的除数,但尚不清楚在考虑步骤 1 时,在每个步骤中找到最大的除数将导致最少的步骤。也许在早期使用不是最大的除数会导致最少的步骤?
【解决方案3】:
 int minmoves(int n){
    if(n<=3){
        return n;
    }
    int[] dp=new int[n+1];
    Arrays.fill(dp,-1);
    dp[0]=0;
    dp[1]=1;
    dp[2]=2;
    dp[3]=3;
    int sqr;
    for(int i=4;i<=n;i++){
        sqr=(int)Math.sqrt(i);
        int best=Integer.MAX_VALUE;
        while(sqr >1){
            if(i%sqr==0){
                int fact=i/sqr;
                best=Math.min(best,1+dp[fact]);
            }
            sqr--;
        }
        best=Math.min(best,1+dp[i-1]);
        dp[i]=best;
    }
    return dp[n];
}

【讨论】:

  • 这似乎是一个 Java 代码,并且 OP 为 C 标记。纯代码的答案通常没有帮助。
猜你喜欢
  • 1970-01-01
  • 2017-01-28
  • 2012-03-03
  • 1970-01-01
  • 2012-05-09
  • 1970-01-01
  • 2012-01-06
  • 2021-10-21
  • 2015-06-07
相关资源
最近更新 更多