Das Knapsack-Problem
Das Knapsack-Problem ist ein bekanntes Optimierungsproblem, bei dem es darum geht, eine Menge von Gegenständen so in einen Rucksack zu packen, dass der Gesamtwert maximiert wird, ohne das Gewichtslimit des Rucksacks zu überschreiten.
unfertig!
Problemstellung
- Gegeben: Eine Menge von Gegenständen, jeder mit einem Gewicht und einem Wert.
- Ziel: Wähle die Gegenstände so aus, dass der Gesamtwert maximiert wird, während das Gesamtgewicht das Limit nicht überschreitet.
Lösungsansätze
- Dynamische Programmierung
- Greedy-Algorithmus
- Brute-Force-Methode
- Backtracking
- Genetische Algorithmen und andere Heuristiken
Dynamische Programmierung
- Teilt das Problem in kleinere Unterprobleme auf.
- Speichert Ergebnisse von Unterproblemen, um doppelte Berechnungen zu vermeiden.
- Effizient für das 0/1 Knapsack-Problem.
Greedy-Algorithmus
- Priorisiert Gegenstände basierend auf einem Kriterium (z.B. Wert/Gewicht-Verhältnis).
- Einfach und schnell, aber nicht immer optimal.
def greedy_knapsack(values, weights, capacity):
# Berechne das Wert-Gewicht-Verhältnis für jeden Gegenstand
ratio = [(v / w, w) for v, w in zip(values, weights)]
# Sortiere die Gegenstände basierend auf dem Verhältnis absteigend
ratio.sort(reverse=True)
total_value = 0
for r, w in ratio:
if capacity >= w:
total_value += r * w
capacity -= w
else:
total_value += r * capacity
break
return total_value
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
print(greedy_knapsack(values, weights, capacity))
Brute-Force-Methode
- Probiert alle möglichen Kombinationen von Gegenständen aus.
- Garantiert eine optimale Lösung, ist aber ineffizient für große Problemstellungen.
from itertools import combinations
def brute_force_knapsack(values, weights, capacity):
n = len(values)
best_value = 0
for r in range(n + 1):
for combo in combinations(range(n), r):
current_weight = sum(weights[i] for i in combo)
current_value = sum(values[i] for i in combo)
if current_weight <= capacity and current_value > best_value:
best_value = current_value
return best_value
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
print(brute_force_knapsack(values, weights, capacity))
Backtracking
- Ähnlich wie Brute-Force, aber verwirft unversprechende Pfade frühzeitig.
- Kann effizienter als reines Brute-Force sein, bleibt jedoch zeitaufwendig.
def knapsack_backtracking(values, weights, capacity, n,
current_value=0, best_value=0):
if n == 0 or capacity == 0:
return max(current_value, best_value)
if weights[n-1] > capacity:
return knapsack_backtracking(values, weights,
capacity, n-1,
current_value, best_value)
else:
tmp1 = knapsack_backtracking(values, weights,
capacity-weights[n-1], n-1,
current_value+values[n-1], best_value)
tmp2 = knapsack_backtracking(values, weights,
capacity, n-1,
current_value, best_value)
best_value = max(tmp1, tmp2)
return best_value
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
n = len(values)
print(knapsack_backtracking(values, weights, capacity, n))
Genetische Algorithmen
- Inspiriert von natürlichen Prozessen wie Evolution und natürlicher Selektion.
- Iterative Verbesserung einer Menge von Lösungen.
- Gut für komplexe Probleme, wo eine näherungsweise Lösung ausreichend ist.
import random
def fitness(individual, values, weights, capacity):
weight = sum(w * ind for w, ind in zip(weights, individual))
value = sum(v * ind for v, ind in zip(values, individual))
if weight > capacity:
return 0
else:
return value
def evolve(population, values, weights, capacity, mutation_rate=0.01):
# Selektion
ranked = sorted([(fitness(individual, values,
weights, capacity), individual)
for individual in population], reverse=True)
population = [individual for _, individual in ranked[:len(ranked)//2]]
# Kreuzung und Mutation
offspring = []
for _ in range(len(population)):
parent1 = random.choice(population)
parent2 = random.choice(population)
child = [parent1[i] if random.random() < 0.5 else parent2[i]
for i in range(len(parent1))]
child = [gene if random.random() > mutation_rate else 1-gene for gene in child]
offspring.append(child)
return offspring + population
def genetic_knapsack(values, weights, capacity, generations=100, population_size=100):
# Initialisiere die Population zufällig
population = [[random.randint(0, 1) for _ in values] for _ in range(population_size)]
for _ in range(generations):
population = evolve(population, values, weights, capacity)
best_individual = sorted([(fitness(individual, values,
weights, capacity), individual)
for individual in population], reverse=True)[0][1]
return sum(v * ind for v, ind in zip(values, best_individual))
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
print(genetic_knapsack(values, weights, capacity))
Zusammenfassung
Das Knapsack-Problem bietet einen Einblick in die Herausforderungen und Ansätze der algorithmischen Optimierung. Die Wahl des richtigen Ansatzes hängt von der spezifischen Problemstellung und den verfügbaren Ressourcen ab.
Das Knapsack-Problem
By Harald Haberstroh
Das Knapsack-Problem
- 99