硬币变化,只是无法做到正确

时间:2010-10-13 23:24:36

标签: c# algorithm coin-change

你好我正在尝试创建一个algorythm,找出我可以改变回来的方式。 但我只是无法正确实现,我一直得到4,我应该得到6,我只是不明白为什么。

这是我在C#中的实现,它是从http://www.algorithmist.com/index.php/Coin_Change

的伪代码创建的
     private static int[] S = { 1, 2, 5 };
        private static void Main(string[] args)
        {
            int amount = 7;
            int ways = count2(amount, S.Length);
            Console.WriteLine("Ways to make change for " + amount + " kr: " + ways.ToString());
            Console.ReadLine();
        }    
static int count2(int n, int m)
        {
        int[,] table = new int[n,m];

        for (int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                // Rules
                // 1: table[0,0] or table[0,x] = 1
                // 2: talbe[i <= -1, x] = 0
                // 3: table[x, j <= -1] = 0

                int total = 0;

                // first sub-problem
                // count(n, m-1)
                if (i == 0) // rule 1
                    total += 1;
                else if (i <= -1) // rule 2
                    total += 0;
                else if (j - 1 <= -1)
                    total += 0;
                else
                    total += table[i, j-1];

                // second sub-problem
                // count(n-S[m], m)
                if (j - 1 <= -1) // rule 3
                    total += 0;
                else if (i - S[j - 1] == 0) // rule 1
                    total += 1;
                else if (i - S[j - 1] <= -1) // rule 2
                    total += 0;
                else
                    total += table[i - S[j-1], j];

                table[i, j] = total;
            }
        }
        return table[n-1, m-1];
    }

5 个答案:

答案 0 :(得分:5)

出于纯粹的深夜无聊(是的,这肯定需要精炼)...它使用递归,linq和一次性产生并且具有与代码行一样多的括号,所以我很对此感到不满......

    static IEnumerable<List<int>> GetChange(int target, IQueryable<int> coins)
    {
        var availableCoins = from c in coins where c <= target select c;
        if (!availableCoins.Any())
        {
            yield return new List<int>();
        }
        else
        {
            foreach (var thisCoin in availableCoins)
            {
                foreach (var result in GetChange(target - thisCoin, from c in availableCoins where c <= thisCoin select c))
                {
                    result.Add(thisCoin);
                    yield return result;
                }
            }
        }
    }

答案 1 :(得分:2)

如果您解释了算法是如何工作的,那将会非常有用。如果没有评论且变量仅以nmi命名,则很难理解其目的。例如,在迭代各种类型的硬币时,您应该使用更具描述性的名称,例如coinType

但是,有些地方对我来说很可疑。例如,您的变量ij会迭代范围1 .. m1 .. n中的值 - 它们总是积极的。这意味着您的规则2和3永远不会运行:

// ...
  else if (i <= -1)     // <- can never be 'true'
    total += 0; 
  else if (j - 1 <= -1) // <- 'true' when 'j == 0'
// ...
  if (j - 1 <= -1)      // <- can never be 'true'
// ...

i永远不会小于或等于-1j

答案 2 :(得分:2)

这是运行顺序的算法。按绿色“播放”箭头运行它。 http://www.exorithm.com/algorithm/view/make_change

我认为主要问题是算法循环应该从-1开始。我认为递归写得更清楚,但这是一个有趣的练习。

答案 3 :(得分:1)

一些观察结果。

1)如果将count函数从伪代码移动到单独的子例程中,它将使代码更简单(并且更不容易出错)。像这样的东西(基于链接中的伪代码)

func count(table, i, j)
  if ( i == 0 ) 
    return 1
  if ( i < 0 )
    return 0
  if ( j <= 0 and i >= 1 )
    return 0

  return table[i][j]
end

然后你可以做

table[i][j] = count(table, i, j - 1) + count(table, i - S[j], j)

在你的内循环中。

2)在count2中,您的第一个循环将发生n - 1次。这意味着,对于n == 1,您将不会进入循环体并且找不到任何解决方案。内循环相同:如果只有一枚硬币,你将找不到任何解决方案。

答案 4 :(得分:1)

我相信你的意思是表[i,j]只使用硬币{0,1,2,...,j - 1}来存储实现i美分值的方法的数量。

本质上,while循环的内部部分表示table [i,j]应该等于在不使用任何硬币j的情况下达到i值的方式的数量,加上实现值的方式的数量我使用至少一个价值为S [j]的硬币。因此,除边界情况外,值为table [i,j - 1] + table [i - S [j],j];总和的第一部分是使用没有值为S [j]的硬币到达i的方式的数量,第二部分是使用至少一个值为S [j]的硬币到达i的方式的数量。

尝试更改:

        // second sub-problem
        // count(n-S[m], m)
        if (j - 1 <= -1) // rule 3
            total += 0;
        else if (i - S[j - 1] == 0) // rule 1
            total += 1;
        else if (i - S[j - 1] <= -1) // rule 2
            total += 0;
        else
            total += table[i - S[j-1], j];

为:

        // second sub-problem
        // count(n-S[m], m)
        if (i - S[j] == 0) // rule 1
            total += 1;
        else if (i - S[j] < 0) // rule 2
            total += 0;
        else
            total += table[i - S[j], j];

仅供参考,编写像(j <0)而不是(j <= -1)这样的东西是标准的。