예제 #1
0
        /// <summary>
        /// Поиск максимального потока
        /// </summary>
        /// <param name="graph">Граф (сеть)</param>
        /// <param name="startVertex">Начальная вершина цепи</param>
        /// <param name="finishVertex">Конечная вершина цепи</param>
        /// <param name="divisionOfVertices">Разбиение множества вершин на два - для построения минимального разреза</param>
        /// <param name="egVis">Элемент управления визуализации графа. В случае null визуализация отсутствует</param>
        /// <returns></returns>
        public int FindMaximalFlow(EduGraph graph, int startVertex, int finishVertex, out List <EdgeInfo> minimalCut, EduGraphVisualizer egVis = null)
        {
            int maximalFlow = 0;                                       // искомая величина максимального потока

            bool[] divisionOfVertices = new bool[graph.VerticesCount]; // разбиение множества вершин на два подмножества (true/false) - для нахождения разреза
            int[]  augmentalPath;
            // Пока у нас есть аугментальная цепь
            while ((augmentalPath = GetAugmentalPath(graph, startVertex, finishVertex, divisionOfVertices)) != null)
            {
                int augmentalFlow = GetAugmentalFlow(graph, augmentalPath, egVis);
                // Визуализация => засыпаем на время
                if (egVis != null)
                {
                    Thread.Sleep(750);
                }
                StartAugmentalFlow(graph, augmentalPath, augmentalFlow);

                // Визуализация => Рисуем изменения
                if (egVis != null)
                {
                    egVis.DrawGraph();
                    egVis.Update();
                }
                // Визуализация => засыпаем на время, чистим метки
                if (egVis != null)
                {
                    Thread.Sleep(1500);
                    graph.ClearVerticesOutsideLabels();
                    egVis.ClearEdgesMarking();
                    egVis.ClearVerticesMarking();
                    egVis.DrawGraph();
                    egVis.Update();
                    Thread.Sleep(1000);
                }
                // Пересоздаём массив посещённых вершин к следующему разу. Если вдруг цепь не найдётся - он сохранится
                divisionOfVertices = new bool[graph.VerticesCount];
            }
            // Суммируем исходящий из истока поток - это и будет максимальным потоком
            foreach (var vertexEdge in graph.Matrix[startVertex].Values)
            {
                maximalFlow += vertexEdge != null ? vertexEdge.Flow : 0;
            }

            // Находим минимальный разрез
            minimalCut = BuildMinimalCut(graph, divisionOfVertices);

            return(maximalFlow);
        }
예제 #2
0
        /// <summary>
        /// Метод нахождения величины дополнительного потока, который можно
        /// пустить по аугментальной цепи
        /// </summary>
        /// <param name="graph">Граф (сеть)</param>
        /// <param name="augmentalPath">Аугментальный путь в виде последовательности ID вершин</param>
        /// <param name="egVis">Элемент управления визуализации графа. В случае null визуализация отсутствует</param>
        /// <returns></returns>
        public int GetAugmentalFlow(EduGraph graph, int[] augmentalPath, EduGraphVisualizer egVis = null)
        {
            int augmentalFlow       = int.MaxValue; // искомое значение аугментального потока
            int augmentalPathLength = augmentalPath.Length;

            for (int curVertexIndex = 0; curVertexIndex < augmentalPathLength; curVertexIndex++)
            {
                // Визуализация => засыпаем на время
                if (egVis != null)
                {
                    Thread.Sleep(400);
                }

                // ID текущей вершины
                int curVertexID = augmentalPath[curVertexIndex];

                // Визуализация => отмечаем текущую вершину
                if (egVis != null)
                {
                    egVis.MarkVertex(graph[curVertexID], Color.Red);
                    egVis.Update();
                }

                // Если вершина первая - просто ставим метку и идём к следующей вершине
                if (curVertexIndex == 0)
                {
                    // Визуализация => ставим метку
                    if (egVis != null)
                    {
                        // Засыпаем на время
                        Thread.Sleep(400);
                        graph[curVertexID].OutsideLabel = $"(+{curVertexID};inf)";
                        egVis.DrawGraph();
                        egVis.Update();
                    }
                    continue;
                }

                // ID предыдущей вершины
                int prevVertexID = augmentalPath[curVertexIndex - 1];

                // Выясняем, по какому ребру мы прошли - прямому, или обратному
                bool isForwardEdge; // прямое ли ребро
                if (graph[prevVertexID, curVertexID] != null)
                {
                    isForwardEdge = true;
                }
                else
                {
                    isForwardEdge = false;
                }

                // Визуализация => отмечаем дугу, по которой пришли
                if (egVis != null)
                {
                    if (isForwardEdge)
                    {
                        egVis.MarkEdge(graph[prevVertexID, curVertexID], Color.Red);
                    }
                    else
                    {
                        egVis.MarkEdge(graph[curVertexID, prevVertexID], Color.Red);
                    }
                    egVis.Update();
                }

                // Выясняем, какой поток можно пропустить по пути, которым мы прошли
                if (isForwardEdge)
                {
                    augmentalFlow = Math.Min(augmentalFlow, graph[prevVertexID, curVertexID].GetAugmentalFlow());
                }
                else
                {
                    augmentalFlow = Math.Min(augmentalFlow, graph[curVertexID, prevVertexID].Flow);
                }

                // Визуализация => ставим метку на эту вершину
                if (egVis != null)
                {
                    // Определяем знак в метке, который ставится перед предыдущей вершиной
                    char sign = isForwardEdge ? '+' : '-';
                    // Засыпаем на время
                    Thread.Sleep(400);
                    // Ставим на вершину метку
                    graph[curVertexID].OutsideLabel = $"({sign}{prevVertexID};{augmentalFlow})";
                    egVis.DrawGraph();
                    egVis.Update();
                }
            }
            return(augmentalFlow);
        }