C# C无递归计数项

C# C无递归计数项,c#,recursion,C#,Recursion,我需要解决一个测试问题,当X苹果作为起始数量,Y苹果每次吃,每次吃苹果加1苹果时,我需要计算总共可以吃多少个苹果 我当前的解决方案使用递归函数,因此,如果Y小于X,或者给定的X太大,则会导致无限循环 public class Apples { // Counts iterations. If we eat less than we add new every, it'll loop infinetely! private static int _recursions;

我需要解决一个测试问题,当X苹果作为起始数量,Y苹果每次吃,每次吃苹果加1苹果时,我需要计算总共可以吃多少个苹果

我当前的解决方案使用递归函数,因此,如果Y小于X,或者给定的X太大,则会导致无限循环

public class Apples
{
    // Counts iterations. If we eat less than we add new every, it'll loop infinetely!
    private static int _recursions;

    private static int _applesRemaining;
    private static int _applesEaten;


    public static int CountApples(int startingAmount, int newEvery)
    {
        if (newEvery > startingAmount) newEvery = startingAmount;
        Console.WriteLine("startingAmount: " + startingAmount + ", newEvery: " + newEvery);

        _applesRemaining = startingAmount;

        /* Eat 'newEvery' amount */
        _applesRemaining -= newEvery;
        _applesEaten += newEvery;

        Console.WriteLine("Eat: " + newEvery + ", remaining: " + _applesRemaining);

        /* Get one additional candy */
        _applesRemaining += 1;
        Console.WriteLine("Added 1.");

        if (_applesRemaining > 1 && _recursions++ < 1000)
        {
            CountApples(_applesRemaining, newEvery);
        }
        else
        {
            if (_recursions > 1000) Console.WriteLine("ABORTED!");

            /* Eat the one we've just added last. */
            _applesEaten += 1;
        }

        return _applesEaten;
    }


    public static void Main(string[] args)
    {
        Console.WriteLine(CountApples(10, 2) + "\n");
    }
}
我手头没有C工具链,所以下面的例子是在Python社区中编辑制作的例子C!魔法

正如评论中所说,这是一个迭代问题,而不是递归问题

var apples = 100;
var eaten = 0;
var eatPerRound = 5;
var gainPerRound = 1;

while(apples > 0)
{
    apples -= eatPerRound;
    eaten += eatPerRound;
    apples += gainPerRound;
    Console.WriteLine($"Round {round}: {eaten} apples eaten, {apples} left");
}

以下是我如何理解您的问题的一个运行示例:

using System.IO;
using System;

class Program
{
    static void Main()
    {
        Console.WriteLine(GetNumberOfApplesEaten(100,5));
    }

    public static int GetNumberOfApplesEaten(int X, int Y)
    {
        int result = 0;

        // while we can eat 'Y' apples
        while(X >= Y)
        {
            // we eat & count those apples
            result += Y;
            X -= Y;
            // we add an extra apple
            X++;
        }
        // we eat what's left
        result += X;

        return result;
    }
}
编辑 我将X>Y更改为X>=Y,使其与您的规格匹配

检查javascript等效项:

函数getNumberOfAppleSatenx,Y{ var结果=0; //而我们可以吃“Y”苹果 whileX>=Y{ //我们吃并数那些苹果 结果+=Y; X-=Y; //我们多加了一个苹果 X++; } //我们吃剩下的 结果+=X; 返回结果; }
logGetNumberOfAppleSaten3,2这个问题的递归似乎有些过分,所以我建议使用另一种数学方法

让我们从一个事实开始,我们总是吃至少X个苹果。真正的问题是,在所有的东西都被吃掉后,总共会添加多少苹果

假设ni是我吃了之后剩下的苹果数。然后:

n0 = X
n1 = X - Y + 1
n2 = X - 2Y + 2
...
ni = X - i(Y - 1)
求解ni=0将得到i——吃所有食物所需的进食次数:

ni = 0 = X - i(Y - 1) => i = X / (Y - 1)
现在我们知道我们要吃多少次了,所以要吃的苹果总数是原来的X加上Y苹果被吃的次数,因为每次我们多吃一个苹果时:

tot = X + roundDown(i) = X * roundDown(X / (Y - 1))
我们对结果进行四舍五入,因为设置ni=0会捕获部分数量的食物,然后会生成部分苹果

例如:

X = 7, Y = 3 => tot = 7 + roundDown(7 / (3 - 1)) = 7 + roundDown(3.5) = 10
starting with 7:
0 eaten, 7 remain
3 eaten, 1 gained, 5 remain
3 eaten, 1 gained, 3 remain
3 eaten, 1 gained, 1 remains
1 eaten, nothing gained, nothing remains
--
10 eaten in total

如果只想计算吃的苹果数而不跟踪进度,则不需要递归和循环。您只需使用线性O1代码计算结果:

int result = apples + apples / (eatenPerRound - 1);
if ((apples % (eatenPerRound - 1)) <= 1) {
    result--;
}
Console.WriteLine($"Total number of {result} apples eaten.");

不确定你的答案是否有限制,但通过一些数学,你可以想出以下方法:

public int CheatEatenApples(int startingApples, int newEvery)
{
    var firstGuess = (double)startingApples*newEvery/(newEvery-1);

    if (firstGuess%1==0) // Checks if firstGuess is a whole number
    {
        return (int)firstGuess-1;
    }
    else
    {
        return (int)firstGuess;
    }
}
第一个猜测是根据我们不断得到新苹果这一事实计算出来的,因此每吃一个苹果,其中一个是免费的!当然,如果第一个猜测是一个整数,那么这实际上就失败了。这就需要免费的苹果才能让我们吃。让我们来看一个例子

如果我们有3个苹果,我们每两个就有一个新苹果,那么我们的第一个猜测是6个苹果。然而,这是三个免费的苹果,我们只有在吃了6个苹果后才能得到第三个,这依赖于三个免费的苹果!所以在这种情况下,我们需要去掉一个。剩下的时间里,我们可以四舍五入删除表示我们离免费苹果有多近的分数部分

这正好说明你在学校学的数学可以在现实世界中使用。以上是一些简单的计算,可能比大多数迭代/递归计算方法要快

附加说明:在一条现已删除的评论中指出,在firstGuess计算中使用整数算法可以更好地实现这一点。这将节省返回值转换回int的时间。它之所以像现在这样写,部分原因是因为我在写它的时候是这样想的,部分原因是当我在迭代寻找正确答案的时候,我在调试时看到了小数部分,以确认只有当firstGuess是完整的,我才需要做一些特别的事情

如果您改为整数数学,那么If条件将需要更改,因为它不再按原样工作,您将得到Sefe的答案

最后说明:

如果您确实希望使用迭代技术,则以下方法与规范相匹配:

public int CalculateEatenApples(int startingApples, int newEvery)
{
    int applesEaten = 0;
    int apples = startingApples;
    while (apples>0)
    {
        applesEaten++;
        apples--;
        if (applesEaten%newEvery==0)
        {
            apples++;
        }
    }
    return applesEaten;
}

这很简单。当你有苹果时,它会增加你吃过的苹果数量,减少你剩下的苹果数量。然后,如果你吃的是newEvery的倍数,那么它会额外增加一个。

Y苹果每次都在吃。你能解释一下吗?知道苹果正在吃真有趣。你是说吃了吗?这听起来像是简化成了一个线性方程,但不管怎样都不需要使用递归。@david,那是个打字错误。更正。当一开始有3个苹果,每次吃5个苹果时会发生什么?看到你的更新后,我想澄清一下:Y苹果不是每次都吃。苹果一次吃一个,每次你达到Y的倍数,你就多加一个苹果。这在其规范中是绝对明确的。是一个我经常使用的在线C编译器,但它的功能并不完善。给定X是3,Y是2,结果应该是5,eat 2,add 1,eat 2,add 1,eat 1,但这段代码返回6。@Bad
只要你有3个,你就去吃,现在你有4个,你吃2个,剩下2个,你去吃,剩下3个,你吃2个,剩下1个,你去吃2个,剩下0个。总数是6。@Baddingtoncat添加额外苹果的顺序很重要。@MineR好的,但这不是我之前评论中的测试题给出的示例。我对此相当怀疑approach@Rafalon怀疑结果是否正确回答了问题?问题是你最多能吃多少苹果?。这个问题已经回答了。请注意,这并没有给出他要求的3次首发,每轮2次进食的结果。。。应该给5分,但给6分。如果你能改变它使其发挥作用,它应该得到最快的投票@Sefe MineR的评论正是我对这一方法持怀疑态度的原因。我不知道您可以使用双%1进行检查。很好。@MineR:我不是100%确定最好的检查方法,所以在@PaulF:我想你可能是对的。上面的方法是结合我脑海中的想法编写的,因为在迭代和测试时,我看到的是小数部分。我现在就不做了。部分原因是,更改为整数算术将意味着更改if条件,而我必须将其更改为的内容将使其与Sefe的答案基本相同至少现在有两个稍有不同的版本可供选择:我后来确实看到了if语句中的细微差别&删除了我的评论。@PaulF:我认为这绝对是一个很好的评论,值得保留,因为现在你已经删除了它,我将在我的答案中添加一条注释这对我有用,非常感谢!我在Y为1的情况下添加了一个检查,这将导致一个无限循环。@Baddingtoncat是的,您肯定应该检查X>0和Y>1
public int CheatEatenApples(int startingApples, int newEvery)
{
    var firstGuess = (double)startingApples*newEvery/(newEvery-1);

    if (firstGuess%1==0) // Checks if firstGuess is a whole number
    {
        return (int)firstGuess-1;
    }
    else
    {
        return (int)firstGuess;
    }
}
public int CalculateEatenApples(int startingApples, int newEvery)
{
    int applesEaten = 0;
    int apples = startingApples;
    while (apples>0)
    {
        applesEaten++;
        apples--;
        if (applesEaten%newEvery==0)
        {
            apples++;
        }
    }
    return applesEaten;
}