简体   繁体   English

F# 中的背包问题与递归 function

[英]Knapsack Problem in F# with recursive function

We have to program the knapsack problem in for a school project in different programming types.我们必须为不同编程类型的学校项目编写背包问题。 One is functional programming and I am trying it in F#.一种是函数式编程,我正在 F# 中尝试。

I am using a recursive function to always get the items with the highest value to put into my knapsack.我正在使用递归 function 始终将具有最高价值的物品放入我的背包中。 At the end I want to have the highest total value of all elements combined.最后,我希望所有元素的总价值最高。 Here is the solution in Python and I just hoped I could transfer it to 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)

This is what I tried in F#.这是我在 F# 中尝试的。 Please help me figuring out my problems.请帮我解决我的问题。 I am new to F# and functional programming and other solutions to the knapsack problem with hundreds of code lines seem overcomplicated.我是 F# 的新手,函数式编程和其他具有数百行代码行的背包问题的解决方案似乎过于复杂。 This doesn´t really print the end result I want to get from this function.这并没有真正打印出我想从这个 function 得到的最终结果。 It just returns 0:它只返回 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

I can't vouch for the correctness or efficiency of the algorithm but this should do what you're looking for:我不能保证算法的正确性或效率,但这应该可以满足您的要求:

 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

Note that because your mutable pack was defined inside of the scope of an if it was inaccessible outside that branch of the if.请注意,因为您的可变包是在 if 的 scope 内部定义的,所以在 if 的该分支之外无法访问它。 I moved that definition above so it could be accessed outside.我将该定义移到上面,以便可以在外部访问它。

I also did a few other changes.我还做了一些其他的改变。 In F# items in a list can be accessed as list.[index].在 F# 中,列表中的项目可以作为 list.[index] 访问。 Parameters are passed separated by spaces not commas as this is a more flexible approach, for example allows currying .参数由空格而不是逗号分隔传递,因为这是一种更灵活的方法,例如允许使用currying

I took the liberty to rewrite your code and I ended up with this.我冒昧地重写了您的代码,最终得到了这个。


    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

The result I get is我得到的结果是

    Name            Profit  Weight
    Sonnenschutz    17      2 
    Duschgel        15      2 
    Shampoo         13      3 
    Zahnpasta       19      4 
    Teller          17      5 
    Trinkflasche    8       3 
                    89      19

Btw.顺便提一句。 if you are interested in learning functional programming using f# I can highly recommend https://fsharpforfunandprofit.com/ .如果您有兴趣使用 f# 学习函数式编程,我强烈推荐https://fsharpforfunandprofit.com/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM