具有递归函数的 F# 中的背包问题
Knapsack Problem in F# with recursive function
我们必须用不同的编程类型为一个学校项目编写背包问题。一种是函数式编程,我正在 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# 的新手,函数式编程和其他解决具有数百个代码行的背包问题似乎过于复杂。这并没有真正打印出我想从此函数获得的最终结果。它只是 returns 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
我不能保证算法的正确性或效率,但这应该可以满足您的需求:
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.
我冒昧地重写了你的代码,结果我得到了这个。
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
我得到的结果是
Name Profit Weight
Sonnenschutz 17 2
Duschgel 15 2
Shampoo 13 3
Zahnpasta 19 4
Teller 17 5
Trinkflasche 8 3
89 19
顺便说一句。如果您有兴趣使用 f# 学习函数式编程,我强烈推荐 https://fsharpforfunandprofit.com/。
我们必须用不同的编程类型为一个学校项目编写背包问题。一种是函数式编程,我正在 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# 的新手,函数式编程和其他解决具有数百个代码行的背包问题似乎过于复杂。这并没有真正打印出我想从此函数获得的最终结果。它只是 returns 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
我不能保证算法的正确性或效率,但这应该可以满足您的需求:
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.
我冒昧地重写了你的代码,结果我得到了这个。
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
我得到的结果是
Name Profit Weight Sonnenschutz 17 2 Duschgel 15 2 Shampoo 13 3 Zahnpasta 19 4 Teller 17 5 Trinkflasche 8 3 89 19
顺便说一句。如果您有兴趣使用 f# 学习函数式编程,我强烈推荐 https://fsharpforfunandprofit.com/。