public void Execute()
        {
            var hNodeDictionary = FUsedGraph.GetNodeDictionary();
            var hNodeCount      = hNodeDictionary.Count;

            // Erstellen der SuperQuelle
            var hSuperSource = new BalancedNode(hNodeCount, 0.0);

            FUsedGraph.TryToAddNode(hSuperSource);

            // Erstellen der SuperSenke
            var hSuperTarget = new BalancedNode(hNodeCount + 1, 0.0);

            FUsedGraph.TryToAddNode(hSuperTarget);

            // Balance der Knoten prüfen und an SuperQuelle und SuperSenke anhängen
            foreach (var hNode in hNodeDictionary.Values)
            {
                var hNodeBalance = ((BalancedNode)hNode).Balance;
                if (hNodeBalance > 0.0)
                {
                    // Es ist eine Quelle. Die SuperQuelle soll nun eine Kante auf diesen Knoten haben. Die Kapazität der Kante entspricht der Balance des Knotens
                    var hNewEdge = new DirectedEdge(hSuperSource, hNode);
                    hNewEdge.AddWeight(new CapacityWeighted(hNodeBalance));
                    FUsedGraph.AddEdge(hNewEdge); // Todo: Prüfen ob es richtig funktioniert
                }
                else if (hNodeBalance < 0.0)
                {
                    // Es ist eine Senke. Dieser Knoten soll nun eine Kante zur SuperSenke haben. Die Kapazität der Kante entspricht der Balance des Knotens
                    var hNewEdge = new DirectedEdge(hNode, hSuperTarget);
                    hNewEdge.AddWeight(new CapacityWeighted(-1.0 * hNodeBalance));
                    FUsedGraph.AddEdge(hNewEdge); // Todo: Prüfen ob es richtig funktioniert
                }
            }

            FUsedGraph.UpdateNeighbourInfoInNodes();


            // Nun soll der Edmonds-Karp Algorithmus ausgeführt werden. Dabei werden die SuperQuelle und SuperSenke verwendet
            var hEdmondsKarpAlgorithm = new EdmondsKarpAlgorithm(FUsedGraph);
            var hFlow = hEdmondsKarpAlgorithm.Execute(hSuperSource.Id, hSuperTarget.Id);


            // Nutzt die SuperQuelle die Kantenkapazitäten voll aus?
            foreach (var hNeighborEdge in hSuperSource.NeighbourEdges)
            {
                var hNeighborEdgeHash = hNeighborEdge.Edge.EdgeHashInfo()[0];
                var hFlowValue        = hFlow[hNeighborEdgeHash];
                var hEdgeCapacity     = hNeighborEdge.Edge.GetWeightValue <CapacityWeighted>();
                if (!hFlowValue.Equals(hEdgeCapacity))
                {
                    // Kein gültiger b-Fluss (Graph kann nicht alles übertragen)
                    FUsedGraph.RemoveNode(hSuperSource);
                    FUsedGraph.RemoveNode(hSuperTarget);
                    Console.WriteLine("Kein Fluss möglich");
                    return;
                }
            }

            // Löschen der SuperQuelle, SuperSenke und den verbindenden Kanten
            FUsedGraph.RemoveNode(hSuperSource);
            FUsedGraph.RemoveNode(hSuperTarget);

            // Den Fluss übernehmen. Dabei aber die Infos zur SuperQuelle und SuperSenke Ignorieren
            var hTotalFlow            = 0.0;
            var hGraphEdgeDictionary  = FUsedGraph.GenerateEdgeHashDictionary();
            var hFlussGraphDictionary = new Dictionary <string, double>();

            foreach (var hEdgeHash in hGraphEdgeDictionary.Keys)
            {
                hFlussGraphDictionary.Add(hEdgeHash, 0.0);
            }
            foreach (var hFlowInfo in hFlow)
            {
                if (hFlussGraphDictionary.ContainsKey(hFlowInfo.Key))
                {
                    hFlussGraphDictionary[hFlowInfo.Key] = hFlowInfo.Value;
                }
            }



            // Solange es noch negative Zyklen gibt
            var hFoundNegativeCycle = true;

            while (hFoundNegativeCycle)
            {
                hFoundNegativeCycle = false;

                // Residualgraphen erstellen
                var hResidualGraph      = ResidualGraphGenerator.GenerateCostCapacity(FUsedGraph, hFlussGraphDictionary);
                var hEdgeHashDictionary = hResidualGraph.GenerateEdgeHashDictionary();

                // Ausgehend von jedem Knoten wird versucht ein negativer Zykel zu finden
                foreach (var hNode in hResidualGraph.GetNodeDictionary())
                {
                    // Negativen Zyklus bezüglich den Kosten suchen
                    var hBellmanFordAlgorithm = new BellmanFordAlgorithm(hResidualGraph);
                    hBellmanFordAlgorithm.Execute(hNode.Value.Id);
                    if (hBellmanFordAlgorithm.HasNegativeCycles)
                    {
                        // Negativen Zyklus gefunden
                        hFoundNegativeCycle = true;

                        // ToDo Auf diesem Zyklus die maximale Kapazität ermitteln
                        var hEdgeHashesOfCycle  = hBellmanFordAlgorithm.CycleEdges;
                        var hMinCapacityInCycle = Double.PositiveInfinity;
                        foreach (var hEdgeInCycleHash in hEdgeHashesOfCycle)
                        {
                            var hEdgeCapcaityValue = hEdgeHashDictionary[hEdgeInCycleHash].GetWeightValue <CapacityWeighted>();
                            if (hEdgeCapcaityValue < hMinCapacityInCycle)
                            {
                                hMinCapacityInCycle = hEdgeCapcaityValue;
                            }
                        }

                        hTotalFlow += hMinCapacityInCycle;

                        // ToDo Fluss auf dem Originalen Graphen entsprechend anpassen (Orginial Kante, Nicht-Original Kante)
                        foreach (var hEdgeInCycleHash in hEdgeHashesOfCycle)
                        {
                            if (ResidualGraphGenerator.HinkantenEdgeHashes.Contains(hEdgeInCycleHash))
                            {
                                // Hinkante
                                // Diese Kante kann ich im Flussgraphen Dictionary direkt ansprechen da die Konten im Hash in der richtigen Reihenfolge stehen
                                hFlussGraphDictionary[hEdgeInCycleHash] += hMinCapacityInCycle;
                            }
                            else if (ResidualGraphGenerator.RueckKantenEdgeHashes.Contains(hEdgeInCycleHash))
                            {
                                // Bei der Breitensuche im Augmentieren Graphen wurde eine Rückkante verwendet.
                                // Diese Rückkante existiert so im originalen Graphen nicht weshalb auch der Hash-Value nicht passt.
                                // Dieser ist lediglich verdreht. Also wird der HashWert vorher noch gespiegelt um die ursprüngliche Kante zu identifizieren
                                var hHashValueOfOriginalEdge = HelpFunctions.InvertEdgeHash(hEdgeInCycleHash);
                                hFlussGraphDictionary[hHashValueOfOriginalEdge] -= hMinCapacityInCycle;
                            }
                        }


                        break;
                    }
                }
            }

            // Kosten des Flusses ermitteln
            var hFlowCost = 0.0;

            foreach (var hEdgeInFlow in hFlussGraphDictionary)
            {
                var hEdge = hGraphEdgeDictionary[hEdgeInFlow.Key];
                hFlowCost += hEdge.GetWeightValue <CostWeighted>() * hEdgeInFlow.Value;
            }

            Console.WriteLine("Kostenminimaler Fluss:\t" + hFlowCost);
        }
Exemple #2
0
        public void Execute()
        {
            var hNodeDictionary = FUsedGraph.GetNodeDictionary();
            var hNodeCount      = hNodeDictionary.Count;

            // Erstellen der SuperQuelle
            var hSuperSource = new Node(hNodeCount);

            FUsedGraph.TryToAddNode(hSuperSource);

            // Erstellen der SuperSenke
            var hSuperTarget = new Node(hNodeCount + 1);

            FUsedGraph.TryToAddNode(hSuperTarget);

            var hPseudoEdges = new List <Edge>();

            // Die SuperQuelle mit den Knoten der Gruppe A verbinden
            for (var hNodeInGroupAId = 0; hNodeInGroupAId < FNodesGroupALimit; hNodeInGroupAId++)
            {
                var hNodeInGroupA = hNodeDictionary[hNodeInGroupAId];
                var hNewEdge      = new DirectedEdge(hSuperSource, hNodeInGroupA);
                hNewEdge.AddWeight(new CapacityWeighted(1));
                FUsedGraph.AddEdge(hNewEdge);
                hPseudoEdges.Add(hNewEdge);
            }

            for (var hNodeInGroupAId = FNodesGroupALimit; hNodeInGroupAId < hNodeCount; hNodeInGroupAId++)
            {
                var hNodeInGroupB = hNodeDictionary[hNodeInGroupAId];
                var hNewEdge      = new DirectedEdge(hNodeInGroupB, hSuperTarget);
                hNewEdge.AddWeight(new CapacityWeighted(1));
                FUsedGraph.AddEdge(hNewEdge);
                hPseudoEdges.Add(hNewEdge);
            }

            FUsedGraph.UpdateNeighbourInfoInNodes();
            var hEdmondsKarpAlgorithm = new EdmondsKarpAlgorithm(FUsedGraph);
            var hFlow = hEdmondsKarpAlgorithm.Execute(hSuperSource.Id, hSuperTarget.Id);


            // PseudoKanten wieder entfernen
            foreach (var hPseudoEdge in hPseudoEdges)
            {
                FUsedGraph.RemoveEdge(hPseudoEdge);
            }
            // Superquelle und -senke wieder entfernen.
            FUsedGraph.RemoveNode(hSuperSource);
            FUsedGraph.RemoveNode(hSuperTarget);

            var hFlowCopy = new List <string>(hFlow.Keys);

            foreach (var hFlowEdge in hFlowCopy)
            {
                var hNodes            = hFlowEdge.Split('-');
                var hEdgeSourceNodeId = Convert.ToInt32(hNodes[0]);
                var hEdgeTargetNodeId = Convert.ToInt32(hNodes[1]);

                if (hEdgeSourceNodeId == hSuperSource.Id)
                {
                    hFlow.Remove(hFlowEdge);
                }
                else if (hEdgeTargetNodeId == hSuperTarget.Id)
                {
                    hFlow.Remove(hFlowEdge);
                }
                else if (hFlow[hFlowEdge] == 0.0)
                {
                    hFlow.Remove(hFlowEdge);
                }
            }

            Console.WriteLine("Die Anzahl der maximalen Matchings beträgt\t" + hFlow.Count);
        }