Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0018: KnapSack

 von 

Beschreibung

Implementierung eines exakten Enumerationsalgorithmus zur Lösung des 0/1-Rucksackproblem .

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Framework-Version(en):

.NET Framework 1.0, .NET Framework 1.1, .NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5

.NET-Version(en):

Visual Basic 2002, Visual Basic 2003, Visual Basic 2005, Visual Basic 2008

Download:

Download des Beispielprojektes [4,31 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2002/2003
' Option Strict:    An
' Option Explicit:  An
'
' Referenzen: 
'  - System
'

' ##############################################################################
' ############################# KnapsackObject.vb ##############################
' ##############################################################################
Option Explicit On 
Option Strict On
Option Compare Binary

' <remarks>
'   Repräsentiert ein Objekt für ein Rucksackproblem.
' </remarks>
Public Class KnapsackObject
    Private m_dblCost As Double
    Private m_dblWeight As Double
    Private m_objId As Object

    ' <summary>
    '   Erstellt eine neue Instanz der Klasse und 
    '   weist den Eigenschaften die in den Parametern
    '   angebenen Werte zu.
    ' </summary>
    ' <param name="dblCost">Kosten des Objekts.</param>
    ' <param name="dblWeight">Gewicht des Objekts.</param>
    ' <param name="objId">ID des Objekts.</param>
    Public Sub New( _
      ByVal dblCost As Double, _
      ByVal dblWeight As Double, _
      ByVal objId As Object)
        Me.Cost = dblCost
        Me.Weight = dblWeight
        Me.Id = objId
    End Sub

    ' <summary>
    '   Gibt die Kosten des Objekts an oder gibt sie zurück.
    ' </summary>
    ' <value>Kosten des Objekts.</value>
    Public Property Cost() As Double
        Get
            Return m_dblCost
        End Get
        Set(ByVal Value As Double)
            m_dblCost = Value
        End Set
    End Property

    ' <summary>
    '   Gibt das Gewicht des Objekts an oder gibt es zurück.
    ' </summary>
    ' <value>Gewicht des Objekts.</value>
    Public Property Weight() As Double
        Get
            Return m_dblWeight
        End Get
        Set(ByVal Value As Double)
            m_dblWeight = Value
        End Set
    End Property

    ' <summary>
    '   Gibt ein Objekt an oder zurück, das das 
    '   Element eindeutig identifiziert.
    ' </summary>
    ' <value>ID des Objekts.</value>
    Public Property Id() As Object
        Get
            Return m_objId
        End Get
        Set(ByVal Value As Object)
            m_objId = Value
        End Set
    End Property

    ' <summary>
    '   Gibt einen String zurück, der die Objektinstanz repräsentiert.
    ' </summary>
    ' <returns>String, der die Objektinstanz repräsentiert.</returns>
    Public Overrides Function ToString() As String
        Return "ID = """ & Me.Id.ToString() & """, _Cost = " & _
          Me.Cost.ToString() & _
          ", Weight = " & Me.Weight.ToString()
    End Function
End Class
' ##############################################################################
' ############################ KnapsackSolution.vb #############################
' ##############################################################################
Option Explicit On 
Option Strict On
Option Compare Binary

Imports Microsoft.VisualBasic

' <remarks>
'   Repräsentiert eine Lösung eines Rucksackproblems.
' </remarks>
Public Class KnapsackSolution
    Private m_dblTotalCost As Double
    Private m_akobjSelectedObjects() As KnapsackObject

    ' <summary>
    '   Gibt die Gesamtkosten der Objekte der Lösung 
    '   an oder gibt sie zurück.
    ' </summary>
    ' <value>Gesamtkosten der Objekte der Lösung.</value>
    Public Property TotalCost() As Double
        Get
            Return m_dblTotalCost
        End Get
        Set(ByVal Value As Double)
            m_dblTotalCost = Value
        End Set
    End Property

    ' <summary>
    '   Gibt ein Array von <c>KnapsackObject</c>-Objekten 
    '   an oder zurück, die eine Lösung eines
    '   Rucksackproblems darstellen.
    ' </summary>
    ' <value>Array von <c>KnapsackObject</c>-Objekten, die 
    '  eine Lösung eines Rucksackproblems darstellen.</value>
    Public Property SelectedObjects() As KnapsackObject()
        Get
            Return m_akobjSelectedObjects
        End Get
        Set(ByVal Value() As KnapsackObject)
            m_akobjSelectedObjects = Value
        End Set
    End Property

    ' <summary>
    '   Gibt einen String zurück, der die Objektinstanz repräsentiert.
    ' </summary>
    ' <returns>String, der die Objektinstanz repräsentiert.</returns>
    Public Overloads Function ToString() As String
        Dim s As String = _
            "TotalCost = " & Me.TotalCost.ToString() & _
            ControlChars.NewLine & _
            "SelectedObjects = {"
        If Me.SelectedObjects.Length > 0 Then
            s &= _
                ControlChars.NewLine & _
                "    (" & Me.SelectedObjects(0).ToString() & ")"
        End If
        If Me.SelectedObjects.Length > 1 Then
            Dim i As Integer
            For i = 1 To Me.SelectedObjects.Length - 1
                s &= _
                    "," & ControlChars.NewLine & _
                    "    (" & Me.SelectedObjects(i).ToString() & ")"
            Next i
        End If
        Return _
            s & ControlChars.NewLine & _
            "}"
    End Function
End Class
' ##############################################################################
' ############################# KnapsackSolver.vb ##############################
' ##############################################################################
Option Explicit On 
Option Strict On
Option Compare Binary

Imports System
Imports System.Collections

' <remarks>
'   Ermittelt eine Lösung für ein 0/1-Rucksackproblem.
' </remarks>
Public Class KnapsackSolver
    Private m_akobjObjects() As KnapsackObject
    Private m_dblKnapsackSize As Double

    ' Beste bisher gefundene Lösung.
    Private m_ablnMaxVec() As Boolean

    ' Maximale bisher gefundene Kosten.
    Private m_dblMaxCost As Double

    ' <summary>
    '   Löst das durch die in der Eigenschaft 
    '  <c>KnapsackSize</c> angegebene Grösse und die in der
    '   Eigenschaft <c>Objects</c> angebenen 
    '   <c>KnapsackObject</c>-Objekte spezifizierte Rucksackproblem
    '   und gibt die Lösung zurück.
    ' </summary>
    ' <returns>Lösung in Form eines 
    '    <c>KnapsackSolution</c>-Objekts.</returns>
    ' <exeption name="Exception">
    '   Wird geworfen, wenn die Eigenschaft <c>Objects</c> 
    '   nicht initialisiert wurde.
    ' </exception>
    Public Function Solve() As KnapsackSolution
        If Me.Objects Is Nothing Then
            Throw New Exception( _
              "Die Eigenschaft Objects muss ein gültiges Array" & _
              " von KnapsackObject-Objekten enthalten.")
        Else
            m_dblMaxCost = 0
            m_ablnMaxVec = New Boolean(Me.Objects.Length - 1) {}
            Dim v() As Boolean = New Boolean(Me.Objects.Length - 1) {}

            ' Enumeration durchführen.
            Enumerate(-1, 0, 0, v)

            ' Da Arrays sehr unflexibel sind und wir auch 
            ' keine ArrayList verwenden wollten, müssen
            ' wir hier zuerst eine ArrayList der gewählten 
            ' Elemente erstellen und diese dann in ein
            ' Array kopieren.
            Dim ks As KnapsackSolution = New KnapsackSolution()
            ks.TotalCost = m_dblMaxCost
            Dim i As Integer
            Dim al As New ArrayList()
            For i = 0 To m_akobjObjects.Length - 1
                If m_ablnMaxVec(i) Then
                    al.Add(m_akobjObjects(i))
                End If
            Next i
            Dim akobj() As KnapsackObject = _
              New KnapsackObject(al.Count - 1) {}
            For i = 0 To al.Count - 1
                akobj(i) = CType(al(i), KnapsackObject)
            Next i
            ks.SelectedObjects = akobj
            Return ks
        End If
    End Function

    ' <summary>
    '   Enumeriert über alle gültigen Lösungen des 
    '   0/1-Ruchsackproblems. Danach findet sich
    '   die Lösung (gefüllter Entscheidungsvektor) in 
    '   den entsprechenden globalen Variablen.
    ' </summary>
    Private Sub Enumerate( _
      ByVal z As Integer, _
      ByVal vcost As Double, _
      ByVal vweight As Double, _
      ByRef v As Boolean())
        Dim i As Integer
        If vweight <= Me.KnapsackSize Then
            If vcost > m_dblMaxCost Then
                m_dblMaxCost = vcost
                For i = 0 To v.Length - 1
                    m_ablnMaxVec(i) = v(i)
                Next i
            End If
            For i = z + 1 To Me.Objects.Length - 1
                v(i) = True
                Enumerate(i, vcost + Me.Objects(i).Cost, _
                  vweight + Me.Objects(i).Weight, v)
                v(i) = False
            Next i
        End If
    End Sub

    ' <summary>
    '   Gibt ein Array von <c>KnapsackObject</c>-Objekten 
    '   an oder gibt es zurück, die als Eingabedaten
    '   für die Methode <c>Solve</c> verwendet werden sollen.
    ' </summary>
    ' <value>Objekte, die das Problem charakterisieren.</value>
    Public Property Objects() As KnapsackObject()
        Get
            Return m_akobjObjects
        End Get
        Set(ByVal Value() As KnapsackObject)
            m_akobjObjects = Value
        End Set
    End Property

    ' <summary>
    '   Gibt die Grösse des Rucksacks an oder gibt sie zurück.
    ' </summary>
    ' <value>Grösse des Rucksacks.</value>
    Public Property KnapsackSize() As Double
        Get
            Return m_dblKnapsackSize
        End Get
        Set(ByVal Value As Double)
            m_dblKnapsackSize = Value
        End Set
    End Property
End Class
' ##############################################################################
' ################################## Main.vb ###################################
' ##############################################################################
Option Explicit On 
Option Strict On
Option Compare Binary

Imports System

' <remarks>
'   Stellt den Einsprungspunkt der Anwendung bereit.
' </remarks>
Public Class Main

    ' <summary>
    '   Der Einsprungspunkt der Anwendung.
    ' </summary>
    Public Shared Sub Main()

        ' Knapsack-Solver mit Beispieldaten vorbereiten.
        Dim ks As New KnapsackSolver()
        ks.KnapsackSize = 14.2
        ks.Objects = New KnapsackObject() { _
            New KnapsackObject(12.1, 7.9, 1), _
            New KnapsackObject(1.2, 12.1, 2), _
            New KnapsackObject(7.9, 3.5, 3), _
            New KnapsackObject(3.5, 1.2, 4), _
            New KnapsackObject(9.6, 9.6, 5) _
        }

        ' Knapsack-Problem lösen.
        Console.WriteLine(ks.Solve().ToString())
    End Sub
End Class

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 3 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von rxmgsfocgsc am 14.04.2011 um 15:19

L8GqvV <a href="http://sccuvhspxefv.com/">sccuvhspxefv</a>, [url=http://svoklbnzzgue.com/]svoklbnzzgue[/url], [link=http://bjnwiynrccip.com/]bjnwiynrccip[/link], http://viwqqmvmzqau.com/

Kommentar von HomerS am 12.02.2009 um 20:18

Hier euer Code^^ - Viva F#

#light 

Let rec Knapsack valueSum costSum costThreshold values costs data n max =
If n <= max Then

Let CostSum = If n = 0 Then costSum Else costSum + (float (List.hd data)) * (costs n)
Let ValueSum = If n = 0 Then valueSum Else valueSum + (float (List.hd data)) * (values n)

If CostSum > costThreshold Then
(costSum, valueSum, List.tl data)
Else
Let (cost1, value1, data1) = Knapsack ValueSum CostSum costThreshold values costs (0 :: data) (n + 1) max
Let (cost2, value2, data2) = Knapsack ValueSum CostSum costThreshold values costs (1 :: data) (n + 1) max

If value1 > value2 Then (cost1, value1, data1) Else (cost2, value2, data2)
Else
(costSum, valueSum, List.tl data)

Let SolveKnapsack numItems costThreshold valueFunc costFunc =
Knapsack 0.0 0.0 costThreshold valueFunc costFunc [] 0 numItems

Type 'a Item = { ID : 'a ; Cost : float; Value : float }

Let Items =
[| { Value = 12.1; Cost = 7.9; ID = 1};
{ Value = 1.2; Cost = 12.1; ID = 2};
{ Value = 7.9; Cost = 3.5; ID = 3};
{ Value = 3.5; Cost = 1.2; ID = 4};
{ Value = 9.6; Cost = 9.6; ID = 5} |]

Let valueFunc idx = Items.[idx - 1].Value
Let costFunc idx = Items.[idx - 1].Cost

Let costThreshold = 14.2

Let (cost, value, data) = SolveKnapsack Items.Length costThreshold valueFunc costFunc

Let selectedItems = (List.zip (List.rev data) [1..data.Length]) |> List.choose (fun (n, idx) -> If n <> 0 Then Some(Items.[idx - 1]) Else None)

printfn "Kosten: %f\nWert: %f\n" cost value

For It in selectedItems Do
printfn "> ID: %A" It.ID

System.Console.ReadKey() |> ignore


Kommentar von HomerS am 23.06.2007 um 13:08

Hi, ich bin relativ neu in .NET, aber ich habe das Rucksackproblem mit einem genetischen Algorithmus gelöst.
Ist euer Ansatz besser?

MFG