找到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中所有可能的变化组合 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

但现在我的程序只是打印

500韩元=>0 100韩元=>500

一切都结束了。如何解决此问题?

一些一般建议
  • 当递归是一个选项时,避免像
    while
    ref
    这样的命令式结构

  • 使函数可读。函数名和变量名不清楚它应该做什么。几句话也没什么坏处

  • 将问题分成更容易解决的子部分。(当您已经知道如何解决它时,这通常会更容易,因此在第一次尝试之后重写您的解决方案是完全可以的。)

  • 一些具体的建议 让我们把这个问题表述为
    val allPossiblePayments:int->int list->int list
    so
    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]
    的处理方式相同,结果中只应包括其中一个)。在这里,组合可能是正确的选择。因此,测试这些函数本身就成了一个小问题(比较排列/组合)

    为置换求它 即使同样的硬币组合会以这种方式出现好几次,它还是有点简单

    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]
    的处理方式相同,只应将其中一个包含在结果中)