找到sml中所有可能的变化组合 fun-pp(amt)= 让 val c_50=参考值0; val c_10=参考值0; val c_x=参考0 在里面 虽然c_50 0 100韩元=>5 500韩元=>1100韩元=>0
但现在我的程序只是打印 500韩元=>0 100韩元=>500 一切都结束了。如何解决此问题?一些一般建议找到sml中所有可能的变化组合 fun-pp(amt)= 让 val c_50=参考值0; val c_10=参考值0; val c_x=参考0 在里面 虽然c_50 0 100韩元=>5 500韩元=>1100韩元=>0,sml,Sml,但现在我的程序只是打印 500韩元=>0 100韩元=>500 一切都结束了。如何解决此问题?一些一般建议 当递归是一个选项时,避免像while和ref这样的命令式结构 使函数可读。函数名和变量名不清楚它应该做什么。几句话也没什么坏处 将问题分成更容易解决的子部分。(当您已经知道如何解决它时,这通常会更容易,因此在第一次尝试之后重写您的解决方案是完全可以的。) 一些具体的建议 让我们把这个问题表述为val allPossiblePayments:int->int list->int listso
while
和ref
这样的命令式结构val allPossiblePayments:int->int list->int list
soallPossiblePayments sum coins
列出了从coins
中提取的所有可能的硬币支付选项,这些硬币的总和是sum
。我们可以假设sum>=0
,并且所有硬币都是正数,或者我们可以使函数健壮并检查这一点
fun pp(amt)=
let
val c_50=ref 0;
val c_10=ref 0;
val c_x=ref 0
in
while !c_50 <= (amt div 500) do
(while !c_10 <= (amt div 100) do
(if ((500 * !c_50) + (100 * !c_10)) = amt
then print("500won =>" ^ Int.toString(!c_50) ^
" 100won =>" ^ Int.toString(!c_10) ^ "\n")
else
c_x := !c_x +1 -1;
c_10 := !c_10+1);
c_50 := !c_50+1)
end;
val allPossiblePayments_1 = allPossiblePayments 0 [1, 2, 5] = [[]]
val allPossiblePayments_2 = allPossiblePayments 5 [1, 2, 5]
(* should contain [5], [2, 2, 1], [2, 1, 1, 1] and [1, 1, 1, 1, 1] *)
allPossiblePayments\u 2
和allPossiblePayments\u 3
表示为适当的测试(返回bool或抛出异常)的原因是有点困难:我们没有完全指定“支付选项”是否包括相同硬币的不同顺序(排列;例如[1,2]
和[2,1]
的处理方式不同,两者都应包括在结果中)或不包括(组合;例如,[1,2]
和[2,1]
的处理方式相同,结果中只应包括其中一个)。在这里,组合可能是正确的选择。因此,测试这些函数本身就成了一个小问题(比较排列/组合)
为置换求它
即使同样的硬币组合会以这种方式出现好几次,它还是有点简单
val allPossiblePayments_3 = allPossiblePayments 11 [2, 5]
(* should contain [[5, 2, 2, 2]] *)
我们看到所有这些都是有效的,但有些是其他的排列
为组合求解它
仅获取组合可能有点棘手。一个糟糕的方法是生成所有排列,对它们进行排序,然后删除重复项。这是不好的,因为我们产生了不必要的结果,却又花了更多的精力去摆脱它们
更好的方法是按排序顺序生成它们,并在生成时排除重复项。只有当一枚硬币大于或等于结果中最大的一枚硬币时,才可以在结果的开头加上一枚硬币
- allPossible 5 [1,2,5];
val it = [[1,1,1,1,1],[1,1,1,2],[1,1,2,1],[1,2,1,1]
,[1,2,2],[2,1,1,1],[2,1,2],[2,2,1],[5]] : int list list
使用此版本的putInFront
而不是旧版本进行测试
fun putInFront _ [] = []
| putInFront validCoin ((coin::subResult)::subResults) =
if validCoin >= coin
then (validCoin::coin::subResult) :: putInFront validCoin subResults
else putInFront validCoin subResults
| putInFront validCoin ([]::subResults) = [validCoin] :: putInFront validCoin subResults
我们必须扔掉所有的(validCoin::coin::subResult)
,这一点并不十分明显。另一种选择可能是当validCoin
时,只丢弃validCoin
并保留coin::subResult
。如果我们这样做,我们会得到一些奇怪的部分结果
- allPossible 5 [5,2,1];
val it = [[5],[2,2,1],[2,1,1,1],[1,1,1,1,1]] : int list list
相反,人们可能会认为,如果validCoin
,其中validCoin
是一些硬币,coin
是部分结果coin::subResult
中最大的硬币,然后,包含了validCoin
的解决方案已经被计数,并且这次可以扔掉validCoin
清理
下面是上述代码的一个清理版本,以及一些解释和想法
- allPossible 5 [5,2,1];
val it = [[5],[2,2,1],[2,2],[2,1,1,1],[2,2],[2,1,1],[2,1],[2],[1,1,1,1,1]] : int list list
fun-putfont c=
List.mapPartial
(fn cs=>案例cs
[]=>一些[c]
|(cmax::)=>如果c>=cmax,则一些(c::cs)其他无)
fun concatMap f xs=List.concat(List.map f xs)
所有可能的0=[]
|所有可能的硬币=
让val validCoins=List.filter(fn coin=>coin putInFront coin(所有可能的(总和硬币)validCoins))validCoins结束
有趣的所有可能的付款=
如果n<0,则raise Fail“无法处理负数”否则
如果List.exists(fn c=>c)存在一些一般性建议
当递归是一个选项时,避免像while
和ref
这样的命令式结构
让你的函数可读。函数名和变量名不清楚它应该做什么。几个注释也没什么坏处
将问题分为更容易解决的子部分(当你知道如何解决问题时,这通常会更容易,因此在第一次尝试后重写你的解决方案是完全好的)
一些具体的建议
让我们把这个问题表述为val-allPossiblePayments:int->int-list->int-list-list
所以allPossiblePayments-sum-coins
列出了从coins
中提取的所有可能的硬币的支付选项,这些硬币的总和为sum
。我们可以假设sum>=0
,并且所有的硬币都是正数,或者我们可能会做出错误的判断该功能非常健壮,请检查是否存在此问题
fun pp(amt)=
let
val c_50=ref 0;
val c_10=ref 0;
val c_x=ref 0
in
while !c_50 <= (amt div 500) do
(while !c_10 <= (amt div 100) do
(if ((500 * !c_50) + (100 * !c_10)) = amt
then print("500won =>" ^ Int.toString(!c_50) ^
" 100won =>" ^ Int.toString(!c_10) ^ "\n")
else
c_x := !c_x +1 -1;
c_10 := !c_10+1);
c_50 := !c_50+1)
end;
所有硬币除以总金额的特殊情况:
val allPossiblePayments_1 = allPossiblePayments 0 [1, 2, 5] = [[]]
非选项时的情况:
val allPossiblePayments_2 = allPossiblePayments 5 [1, 2, 5]
(* should contain [5], [2, 2, 1], [2, 1, 1, 1] and [1, 1, 1, 1, 1] *)
我没有将allPossiblePayments\u 2
和allPossiblePayments\u 3
表示为适当的测试(返回bool或抛出异常)的原因是有点困难:我们没有完全指定“支付选项”是否包括相同硬币的不同顺序(排列;例如[1,2]
和[2,1]
的处理方式不同,两者都应包括在结果中)或不包括(组合;例如,[1,2]
和[2,1]
的处理方式相同,只应将其中一个包含在结果中)