【问题标题】:Knapsack Problem in F# with recursive functionF#中带有递归函数的背包问题
【发布时间】:2020-10-07 11:39:09
【问题描述】:

我们必须以不同的编程类型为一个学校项目编写背包问题。一种是函数式编程,我正在 F# 中尝试。

我正在使用递归函数来始终将具有最高价值的物品放入我的背包中。最后,我希望所有元素的总价值最高。这是 Python 中的解决方案,我只是希望我可以将它转移到 F#。

    let names = ["Zahnbürste","Zahnpasta", "Teller", "Duschgel", "Shampoo", "Handtuch", "Besteck", "Trinkflasche", "Becher", "Taschenlampe", "Sonnenschutz", "Medikamente"]
let volumes = [2,4,5,2,2.5,10,5,3,3,9,2,1]
let values = [3,19,17,15,13,3,2,8,5,6,17,15]
    maxVol = 20;

def rucksackProblem(restVol, i) :
if (i < (len(volumes))) :
    dontPack = rucksackProblem(restVol, i + 1)

    pack = 0
    if (restVol - volumes[i] >= 0) :
        pack = values[i] + rucksackProblem(restVol - volumes[i], i + 1)
    if (dontPack > pack) :
        return dontPack
    else :
        return pack
else :
    return 0


result = rucksackProblem(maxVol, 0)
print(result)

这是我在 F# 中尝试过的。请帮我解决我的问题。我是 F# 新手,函数式编程和其他具有数百行代码行的背包问题的解决方案似乎过于复杂。这并没有真正打印出我想从这个函数中得到的最终结果。它只返回 0:


   open System

let names_list = ["Zahnbürste";"Zahnpasta"; "Teller"; "Duschgel";"Shampoo"; "Handtuch"; "Besteck"; "Trinkflasche"; "Becher";"Taschenlampe";"Sonnenschutz";"Medikamente"]
let volumes_list = [2;4;5;2;3;10;5;3;3;9;2;1]
let values_list = [3;19;17;15;13;3;2;8;5;6;17;15]
let maxVolume = 20
let rec rucksackProblem (restVol : int, i : int) =
    if i < volumes_list.Length then
       let dontPack = rucksackProblem(restVol, i + 1) 
       let pack = 0
       let currentVolumeItem = volumes_list.Item(i)
       if restVol - volumes_list.Item(i) >= 0 then
        let mutable pack = values_list.Item(i) + rucksackProblem(restVol - volumes_list.Item(i), i + 1)
        printf "%i" (volumes_list.Item(i))
        else()
       if dontPack > pack then
        dontPack
        else 
            pack

    else
        0

let result = rucksackProblem(maxVolume, 0)
printfn "%i" result


Console.ReadKey() |> ignore

【问题讨论】:

    标签: functional-programming f# knapsack-problem


    【解决方案1】:

    我冒昧地重写了你的代码,最终得到了这个。

    let names = ["Zahnbürste"; "Zahnpasta"; "Teller"; "Duschgel"; "Shampoo"; "Handtuch"; "Besteck"; "Trinkflasche"; "Becher"; "Taschenlampe"; "Sonnenschutz"; "Medikamente"] let weights = [2; 4; 5; 2; 3; 10; 5; 3; 3; 9; 2; 1] let profits = [3; 19; 17; 15; 13; 3; 2; 8; 5; 6; 17; 15] let cap = 20 type Product = { Name: string; Profit: int; Weight: int } let knappsack names profits weights cap = let sortItemsInDecreasingOrder = List.zip3 names profits weights |> List.map (fun x -> { Name=x.Item1; Profit=x.Item2; Weight=x.Item3 }) |> List.sortBy (fun p -> p.Profit / p.Weight) |> List.rev let products = sortItemsInDecreasingOrder let rec pack bag totalWeight idx = if idx > List.length names - 1 then bag else let p = products.[idx] if (totalWeight + p.Weight) > cap then bag else pack (bag @ [p]) (totalWeight + p.Weight) (idx + 1) pack List.empty 0 1 knappsack names profits weights cap |> Dump |> ignore

    我得到的结果是

    名称 利润权重 松嫩舒茨 17 2 杜施格尔 15 2 洗发水 13 3 扎恩帕斯塔 19 4 柜员 17 5 Trinkflasche 8 3 89 19

    顺便说一句。如果你有兴趣使用 f# 学习函数式编程,我强烈推荐 https://fsharpforfunandprofit.com/

    【讨论】:

    • 这不是一个非常有效的方法。排序至少是 O(n log n) 但最坏情况是 O(n^2) OP 的预期算法平均情况是 O(nw) 最坏情况 O(2^n) 见en.wikipedia.org/wiki/Knapsack_problem
    • 这很有趣,也是另一种可以理解的方法。 Stackoverflow 上有更长的背包问题的解决方案。因为我想在我的同学面前解释这会做得更好! :)
    • @Tammo 完美。我很高兴它有帮助!
    【解决方案2】:

    我不能保证算法的正确性或效率,但这应该可以满足您的要求:

     open System
    
    let names_list = ["Zahnbürste";"Zahnpasta"; "Teller"; "Duschgel";"Shampoo"; "Handtuch"; "Besteck"; "Trinkflasche"; "Becher";"Taschenlampe";"Sonnenschutz";"Medikamente"]
    let volumes_list = [2;4;5;2;3;10;5;3;3;9;2;1]
    let values_list = [3;19;17;15;13;3;2;8;5;6;17;15]
    let maxVolume = 20
    
    let rec rucksackProblem (restVol : int)  (i : int) =
        if i < volumes_list.Length then
           let dontPack = rucksackProblem restVol (i + 1) 
    
           let currentVolumeItem = volumes_list.[i]
    
           let pack =  
                if restVol - volumes_list.[i] >= 0 then 
                  values_list.[i] + rucksackProblem (restVol - volumes_list.[i])  (i + 1)
                else 0  
    
           if dontPack > pack then
                dontPack
           else 
                pack
    
        else
            0
    
    let result = rucksackProblem maxVolume 0
    printfn "%i" result
    

    请注意,因为您的可变包是在 if 的范围内定义的,所以在 if 的该分支之外无法访问它。我把这个定义移到了上面,这样就可以在外面访问了。

    我还做了一些其他更改。在 F# 中,列表中的项目可以作为 list.[index] 访问。参数以空格而不是逗号分隔,因为这是一种更灵活的方法,例如允许currying

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 2020-11-12
    相关资源
    最近更新 更多