/** * Beispiel aus * * - Algorithmen und Datenstrukturen für Dummies * - von Andreas Gogol-Döring und Thomas Letschert * - Verlag Wiley-VCH; Oktober 2019 * - Kapitel 8, Rucksack packen * @author A. Gogol-Döring, Th. Letschert */ import Foundation struct AuD_08_02_KnapsackBruteForce { /* * Im Pseudocode wird eine Menge und ihre Teilmengen verwendet. Das ist * wieder nicht so zu verstehen, dass im Code mit dem Typ Set gearbeitet werden soll. * Es handelt sich um eine Menge von Elementen, die in irgendeiner Datstruktur stecken. * Wir nehmen eine Liste als Datenstruktur. * * Die Menge aller Teilmengen einer Menge M mit |M| Elementen können wir finden, indem wir alle * Kombinationen von 0 und 1 der Länge |M| als Auswahlfunktion auf M anwenden. * Die Kombinationen können bei bekannter Länge mit geschachtelten for-Schleifen gefunden werden. * Bei unbekannte Länge können die Schleifen rekursiv erzeugt werden: */ static func AllSubListsViaBitSequence(lst: [A]) -> [[A]] { func bitSeqOfLength(n: Int) -> [[Int]] { n == 0 ? [[]] : bitSeqOfLength(n: n-1).flatMap( { s -> [[Int]] in [[0] + s] + [[1] + s] } ) } func allSubLists(lst: [A]) -> [[A]] { bitSeqOfLength(n: lst.count).map { (selection: [Int]) in let zippedWithIndex: [(A, Int)] = Array(zip(lst, Array(0 ..< lst.count))) return zippedWithIndex.flatMap { (itemIndex: (A, Int)) -> [A] in let item = itemIndex.0 let index = itemIndex.1 return (selection[index] == 0) ? [] : [item] } } } return allSubLists(lst: lst) } /* * Es ist nicht notwendig die Folgen von Nullen und Einsen zu bilden. * Man kann auch gleich die Liste der Möglichkeiten auch erzeugen: */ static func AllSubLists(lst: [A]) -> [[A]] { lst.count == 0 ? [[]] : AllSubLists(lst: Array(lst.dropFirst())).flatMap( { s -> [[A]] in [s] + [[lst[0]] + s] } ) } struct Item : Comparable, CustomStringConvertible { let name : String let gewicht: Int let wert: Int var attraktion: Double { Double(wert) / Double(gewicht) } static func > (lhs: Item, rhs: Item) -> Bool { lhs.attraktion > rhs.attraktion } static func < (lhs: Item, rhs: Item) -> Bool { lhs.attraktion < rhs.attraktion } var description: String { "(\(name), \(gewicht), \(wert))" } } static func KnapsackBruteForce(M: [Item], T: Int) -> [Item] { var S_opt: [Item] = [] var w_opt = 0 for s in AllSubLists(lst: M) { let w = s.map( { i in i.wert } ).reduce(0, +) let g = s.map( { i in i.gewicht } ).reduce(0, +) if ((g <= T) && (w > w_opt)) { S_opt = s w_opt = w } } return S_opt } static func run() { let items1: [Item] = [Item(name: "A", gewicht: 7, wert: 42), Item(name: "B", gewicht: 3, wert: 12), Item(name: "C", gewicht: 4, wert: 40), Item(name: "D", gewicht: 5, wert: 25)] let items2: [Item] = [Item( name: "Goldkorn", gewicht: 1, wert: 10), Item(name: "Silberbarren", gewicht: 200, wert: 500)] let items3: [Item] = [Item(name: "Computer", gewicht: 3, wert: 300), Item(name: "TV", gewicht: 12, wert: 200), Item(name: "Uhr", gewicht: 10, wert: 150), Item(name: "Vase", gewicht: 7, wert: 100)] let selection1 = KnapsackBruteForce(M: items1, T: 10) let selection2 = KnapsackBruteForce(M: items2, T: 200) let selection3 = KnapsackBruteForce(M: items3, T: 20) print(selection1.map( { i in i.description } ).joined(separator: ", ") ) print(selection2.map( { i in i.description } ).joined(separator: ", ") ) print(selection3.map( { i in i.description } ).joined(separator: ", ") ) } }