如何使用递归在C#中获得硬币更改问题的最小可能组合
作者:互联网
我是C#的新手,我有一个要解决的递归问题.我希望在这个硬币更换问题中获得最少数量的硬币.我已经为它调整了算法,但我需要返回一个类型为Change的对象,它将包含最小可能的组合.
我试图实现一个算法,但我有所有可能的组合.
using System;
using System.Collections.Generic;
using System.Linq;
// Do not modify change
class Change
{
public long coin2 = 0;
public long bill5 = 0;
public long bill10 = 0;
}
class Solution
{
// Do not modify method signature
public static Change OptimalChange(long s)
{
Change _change = new Change();
//To implement here
return _change;
}
public static int GetCombinations(int total, int index, int[] list, List<int> cur)
{
if (total == 0)
{
foreach (var i in cur)
{
Console.Write(i + " ");
}
Console.WriteLine();
return 1;
}
if (index == list.Length)
{
return 0;
}
int ret = 0;
for (; total >= 0; total -= list[index])
{
ret += GetCombinations(total, index + 1, list, cur);
cur.Add(list[index]);
}
for (int i = 0; i < cur.Count(); i++)
{
while (cur.Count > i && cur[i] == list[index])
{
cur.RemoveAt(i);
}
}
return ret;
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("Hello Change");
int s = 41;
/*Change m = Solution.OptimalChange(s);
Console.WriteLine("Coins(s) 2euros :" + m.coin2);
Console.WriteLine("Bill(s) 5euors :" + m.bill5);
Console.WriteLine("Bill(s) 10euors :" + m.bill10);
long result = m.coin2*2 + m.bill5*5 + m.bill10*10;
Console.WriteLine("\nChange given =", + result);*/
Solution sol = new Solution();
int[] l = {
2,
5,
10
};
Solution.GetCombinations(s, 0, l, new List<int>());
}
}
预期结果
示例:可用的硬币为{2,5,10}
– 我输入了12 –
该计划应该返回
硬币2欧元:1
比尔5个人:0
Bill(s)10euors:1
– 我输入了17 –
该计划应该返回
硬币2欧元:1
比尔5个人:1
Bill(s)10euors:1
解决方法:
首先,了解递归的基本概念是什么:
>如果我们可以在没有递归的情况下解决问题,请解决它并返回解决方案.
>如果我们不能,那么将问题减少到一个或多个较小的问题,递归地解决每个较小的问题,并结合解决方案来解决更大的问题.
其次,了解动态编程的基本思想是什么:
>递归解决方案经常多次重新计算同样的问题;存储解决方案有时更有效,而不是重新计算它.
好吧,让我们来解决你的问题吧.
// Do not modify change
class Change
{
public long coin2 = 0;
public long bill5 = 0;
public long bill10 = 0;
}
Pish tosh.这堂课太可怕了.修理它!
sealed class Change
{
public long Two { get; }
public long Five { get; }
public long Ten { get; }
public Change(long two, long five, long ten)
{
this.Two = two;
this.Five = five;
this.Ten = ten;
}
public Change AddTwo() => new Change(Two + 1, Five, Ten);
public Change AddFive() => new Change(Two, Five + 1, Ten);
public Change AddTen() => new Change(Two, Five, Ten + 1);
public long Count => Two + Five + Ten;
public long Total => Two * 2 + Five * 5 + Ten * 10;
}
从一个可以帮助您的数据结构开始,而不是一个伤害您的数据结构.
现在,让我们编写一个递归函数:
public static Change OptimalChange(long s)
{
// Are we in the base case? Solve the problem.
// If not, break it down into a smaller problem.
}
什么是基本情况?实际上有两个.如果总和为负,则没有解,如果总和为零,则存在零解.
public static Change OptimalChange(long s)
{
if (s < 0)
return null;
if (s == 0)
return new Change(0, 0, 0);
好吧,这很容易.困难的部分是什么?好吧,如果有一个解决方案,那么它有两个,或者它有五个,或者它有十个,对吧?或者也许全部三个.所以让我们找出答案.
public static Change OptimalChange(long s)
{
if (s < 0)
return null;
if (s == 0)
return new Change(0, 0, 0);
Change tryTen = OptimalChange(s - 10)?.AddTen();
...
你能从这里拿走吗?
当您拥有实现所需操作的数据结构时,看看问题会变得多么容易?再次总是创建一个可以帮助您的数据结构.
下一个问题:该算法效率很低.为什么?因为我们不断重做我们已经做过的问题.假设我们正在评估OptimalChange(22).这称为OptimalChange(12),它调用OptimalChange(7),它调用OptimalChange(5).但OptionalChange(12)也调用OptimalChange(10),它再次调用OptimalChange(5).答案没有改变,但我们再次进行计算.
那么我们该怎么办?我们使用动态编程技术.有两种方法可以做到:
>继续递归,并记住递归函数.
>创建一个变更数组,并随时填写.
但等等,问题多于性能问题.我们使问题最小化10次,每次最少2次,但参数很长;它可能是数十亿或数万亿.如果我们有一个递归的解决方案,我们将打击堆栈,如果我们有一个基于阵列的解决方案,它太大了.
在给定的可能输入范围内,我们需要更聪明地解决这个问题.想想吧;我们可以分析地解决问题,没有递归,数组或长时间运行的循环?或者,等效地,有没有办法快速减少极小问题的大问题?然后可以通过动态编程解决小问题.
就像家庭作业问题一样,记住你受到良好学术规则的约束.如果你在家庭作业解决方案中使用SO的想法,你必须给予信任.不这样做是抄袭,如果你坚持下去,你会被驱逐出体面的学校.
标签:c,dynamic-programming,coin-change 来源: https://codeday.me/bug/20190716/1473786.html