使用动态编程进行更改的所有解决方案
all solutions to change making with dynamic programming
我在复习算法课的讲义时,开始思考这个问题:
给定具有不同价值的不同类型的硬币,找到所有硬币配置,将其相加为一定的总和,而不会重复
在课堂上,我们解决了这个问题,找出求和的所有可能方法的数量,以及求和的最少硬币数量。然而,我们从未试图真正找到解决方案。
我在考虑用动态编程来解决这个问题。
我带来了递归版本(为了简单起见,我只打印解决方案):
void solve(vector<string>& result, string& currSoln, int index, int target, vector<int>& coins)
{
if(target < 0)
{
return;
}
if(target == 0)
{
result.push_back(currSoln);
}
for(int i = index; i < coins.size(); ++i)
{
stringstream ss;
ss << coins[i];
string newCurrSoln = currSoln + ss.str() + " ";
solve(result, newCurrSoln, i, target - coins[i], coins);
}
}
然而,我在尝试使用DP来解决问题时遇到了困难。我有两个主要障碍:
- 我不知道应该使用什么数据结构来存储以前的答案
- 我不知道我的自下而上的过程(使用循环来替换递归)应该是什么样子
欢迎任何帮助,并将感谢一些代码!
谢谢你抽出时间。
在dp解决方案中,您可以生成一组中间状态,以及有多少种方法可以实现这些状态。那么你的答案是最终处于成功状态的数字。
所以,对于变化计数,状态是指你得到了特定的变化量。计数是做出改变的方式的数量。成功的状态是你做出了正确的改变。
要从计数解决方案到枚举它们,您需要保留这些中间状态,并在每个状态中记录所有转换到该状态的状态,以及有关如何转换的信息。(在零钱计数的情况下,如何添加哪枚硬币。)
现在,有了这些信息,您可以从成功状态开始,递归地通过dp数据结构向后,以实际找到解决方案,而不是计数。好消息是,你所有的递归工作都是有效的——你总是只寻找成功的路径,所以不要在不起作用的事情上浪费时间。但是,如果有10亿个解决方案,那么就没有什么捷径可以快速打印出10亿个方案。
不过,如果你想稍微聪明一点,你可以把它变成一个可用的枚举。例如,你可以说"我知道有4323431个解决方案,第432134个是什么?"找到这个解决方案会很快。
很明显,您可以采用动态编程方法。不明显的是,在大多数情况下(取决于硬币的面额),你可以使用贪婪算法,这可能更有效。参见Cormen,Leiserson,Rivest,Stein:算法导论第二版,问题16.1。
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- visual c++,如何获取解决方案目录中的代码
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- C++Matching Brackets 2解决方案不起作用
- 在 ubuntu3 上C++ goto 定义有什么解决方案吗16.04?
- 自上而下的动态规划与递归朴素解决方案.检查运行时执行
- C++中TSP的动态编程解决方案
- 我该如何判断k-server动态解决方案的最佳路径以数组成本[i] [j] [k] [t]位于何处
- 具有模板化类型的动态类型Singleton.这是可行的方法吗?[提供的解决方案]
- 迭代解决方案作为动态编程
- 如何验证竞争性编程任务的动态编程解决方案的正确性
- 可调整大小的动态二维阵列的更好解决方案
- 具有对齐成员的对象的动态分配-可能的解决方案
- 递归解决方案的动态编程解决方案
- 使用动态编程进行更改的所有解决方案
- 动态规划解决方案-如何解决?(给我指个正确的方向)
- 针对不相关类型的动态调度的解决方案