예제 #1
0
        /// <summary>
        /// Получить вершину на удаление из клики
        /// </summary>
        /// <param name="graph">Граф</param>
        /// <param name="clique">Клика</param>
        /// <param name="oneMissing">Список возможных вершин на удаление</param>
        /// <returns></returns>
        static int GetNodeToDrop(MyGraph graph, List <int> clique, List <int> oneMissing)
        {
            //Если в клике всего одна вершина - ее и вернем
            if (clique.Count == 1)
            {
                return(clique[0]);
            }
            int maxCount = 0;

            for (int i = 0; i < clique.Count; ++i)
            {
                int currCliqueNode   = clique[i];
                int countNotAdjacent = 0;
                //Подсчитаем количество не связанных между собой вершин
                for (int j = 0; j < oneMissing.Count; ++j)
                {
                    int currOneMissingNode = oneMissing[j];
                    if (graph.AreAdjacent(currCliqueNode,
                                          currOneMissingNode) == false)
                    {
                        ++countNotAdjacent;
                    }
                }
                if (countNotAdjacent > maxCount)
                {
                    maxCount = countNotAdjacent;
                }
            }
            List <int> candidates = new List <int>();

            for (int i = 0; i < clique.Count; ++i)
            {
                int currCliqueNode   = clique[i];
                int countNotAdjacent = 0;
                for (int j = 0; j < oneMissing.Count; ++j)
                {
                    int currOneMissingNode = oneMissing[j];
                    if (graph.AreAdjacent(currCliqueNode,
                                          currOneMissingNode) == false)
                    {
                        ++countNotAdjacent;
                    }
                }
                //Если количество пропусков ребер у данной вершины равно максимуму по списку вершин на удаление - добавим эту вершину в список кандидатов на удаление
                if (countNotAdjacent == maxCount)
                {
                    candidates.Add(currCliqueNode);
                }
            }
            //Вернем случайную вершину из списка кандидатов на удаление
            return(candidates[random.Next(0, candidates.Count)]);
        } // GetNodeToDrop
예제 #2
0
        /// <summary>
        /// Получить вершину на добавление к клике
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="possibleAdd">Список возможных вершин на добавление</param>
        /// <returns></returns>
        static int GetNodeToAdd(MyGraph graph, List <int> possibleAdd, List <int> clique)
        {
            //Если возможная вершина всего одна - ее и вернем
            if (possibleAdd.Count == 1)
            {
                return(possibleAdd[0]);
            }
            int        maxDegree  = 0;
            List <int> candidates = new List <int>();

            possibleAdd.ForEach(c =>
            {
                int degreeOfCurrentNode = 0;
                //Вычислим, со сколькими вершинами из списка возможных связана текущая выбранная вершина
                possibleAdd.ForEach(v =>
                {
                    if (graph.AreAdjacent(c, v) == true)
                    {
                        ++degreeOfCurrentNode;
                    }
                });
                //Таким образом получим максимальное значение связанности для вершин из списка возможных
                if (degreeOfCurrentNode > maxDegree)
                {
                    maxDegree = degreeOfCurrentNode;
                }
            });
            //Пройдем по списку возможных вершин и добавим в список кандидатов те из них, для которых степень связанности равна максимальной связанности в данном списке
            possibleAdd.ForEach(c =>
            {
                int degreeOfCurrentNode = 0;
                possibleAdd.ForEach(v =>
                {
                    if (graph.AreAdjacent(c, v) == true)
                    {
                        ++degreeOfCurrentNode;
                    }
                });
                if ((degreeOfCurrentNode == maxDegree) && !(clique.Exists(x => x == c)))
                {
                    candidates.Add(c);
                }
            });
            if (candidates.Count().Equals(0))
            {
                return(-1);
            }
            //Вернем случайную вершину из кандидатов на добавление
            return(candidates[random.Next(0, candidates.Count)]);
        }
예제 #3
0
        static List <int> MakeOneMissing(MyGraph graph, List <int> clique)
        {
            int        count;
            List <int> result = new List <int>();

            for (int i = 0; i < graph.NumberNodes; ++i)
            {
                count = 0;
                //Если число соседей данной вершины меньше размера клики - перейдем к рассмотрению следующей вершины
                if (graph.NumberNeighbors(i) < clique.Count - 1)
                {
                    continue;
                }
                //Если данная вершина уже есть в клике - перейдем к следующей вершине
                if (clique.BinarySearch(i) >= 0)
                {
                    continue;
                }
                //Подсчитаем количество связей данной вершины с вершинами клики
                for (int j = 0; j < clique.Count; ++j)
                {
                    if (graph.AreAdjacent(i, clique[j]))
                    {
                        ++count;
                    }
                }
                if (count == clique.Count - 1)
                {
                    result.Add(i);
                }
            }
            return(result);
        }
예제 #4
0
        static void Main(string[] args)
        {
            try
            {
                graphFile = args[0];
                int   timeLimit = Convert.ToInt32(args[1]);
                Timer myTimer   = new Timer();
                myTimer.Start();
                myTimer.Interval = timeLimit * 1000;
                startTime        = DateTime.Now;
                myTimer.Elapsed += MyTimer_Elapsed;
                MyGraph graph            = new MyGraph(graphFile, "DIMACS");
                int     maxTime          = 100;
                int     targetCliqueSize = graph.NumberNodes;
                //Эвристически найдем хотя бы что-то похожее на максимальную клику (в пределах 5% ошибки - чтобы вернуть, если не успеет обсчитаться основной обход)
                maxClique = FindMaxClique(graph, maxTime, targetCliqueSize);
                int ub = maxClique.Count;
                Bound = ub;
                List <List <int> > clique = new List <List <int> >();
                //Сортируем вершины по числу соседей, будем вызывать алгоритм для тех вершин, у которых количество соседей наибольшее
                Dictionary <int, int> nodeAndNeighbors = new Dictionary <int, int>();
                for (int i = 0; i < graph.NumberNodes; ++i)
                {
                    int numberNeighbors = graph.NumberNeighbors(i);
                    nodeAndNeighbors.Add(i, numberNeighbors);
                }
                //Сортируем вершины по уменьшению количества соседей
                nodeAndNeighbors = nodeAndNeighbors.OrderByDescending(pair => pair.Value).ToDictionary(pair => pair.Key, pair => pair.Value);
                List <int> colors = new List <int>()
                {
                    1
                };
                //Раскраска графа
                int top = (from v in nodeAndNeighbors.Keys.ToList() select v).ToList <int>()[0];
                Dictionary <int, int> colorizedGraph = new Dictionary <int, int>();
                //Раскрасим граф
                colorizedGraph = colorize(nodeAndNeighbors.Keys.ToList <int>(), graph);
                int cntr = 0;
                //Зададим базовую модель
                Cplex       cplex = new Cplex();
                IRange[][]  rng   = new IRange[1][];
                INumVar[][] var   = new INumVar[1][];
                rng[0] = new IRange[graph.NumberNodes * graph.NumberNodes];
                // add the objective function
                double[] objvals = new double[graph.NumberNodes];
                string[] varname = new string[graph.NumberNodes];
                for (int i = 0; i < graph.NumberNodes; i++)
                {
                    objvals[i] = 1.0;
                    varname[i] = "x" + (i + 1);
                }
                INumVar[] x = cplex.NumVarArray(graph.NumberNodes, 0.0, 1.0, varname);
                var[0] = x;
                //Ограничение, что х лежит от нуля до единицы задали при инициализации
                cplex.AddMaximize(cplex.ScalProd(x, objvals));
                //Получим номер максимального цвета = это количество цветов, в которые окрашен граф
                //Будем иметь в виду, что количество цветов - это верхняя оценка на размер клики, а найденная эвристически клика на первом этапе - нижняя оценка.
                int        colorCount     = colorizedGraph.Values.Max();
                List <int> colorizedNodes = new List <int>();
                int        pointer        = 1;
                //Добавим ограничение, что вершины, входящие в один цветовой класс, не связаны между собой
                for (int i = 1; i <= colorCount; ++i)
                {
                    colorizedNodes = (from t in colorizedGraph where t.Value == i select t.Key).ToList <int>();
                    if (colorizedNodes.Count() != 1)
                    {
                        INumExpr[] constraint = new INumExpr[colorizedNodes.Count()];
                        int        counter    = 0;
                        colorizedNodes.ForEach(node =>
                        {
                            constraint[counter] = cplex.Prod(1.0, x[node]);
                            counter++;
                        });
                        rng[0][pointer] = cplex.AddLe(cplex.Sum(constraint), 1.0, "c" + (pointer));
                        pointer++;
                    }
                }
                for (int i = 0; i < graph.NumberNodes; i++)
                {
                    for (int j = i + 1; j < graph.NumberNodes; j++)
                    {
                        if (!graph.AreAdjacent(i, j))
                        {
                            rng[0][pointer] = cplex.AddLe(cplex.Sum(cplex.Prod(1.0, x[i]), cplex.Prod(1.0, x[j])), 1.0, "c" + (pointer));
                            pointer++;
                        }
                    }
                }

                //------------------------------------------------------------------------
                //-----Пробуем решать задачу ровно до тех пор, пока не получим клику------
                //-----Помним про ограничения на размер клики-----------------------------
                int countOfConstraint = colorCount;
                globalClick = maxClique;
                Branching(cplex, x);
                cplex.End();
                ////Максимальная клика, которую можно найти для вершины - это количество различных цветов, в которые окрашены все ее соседи плюс она  сама
                //foreach (KeyValuePair<int,int> pair in nodeAndNeighbors)
                //{
                //        List<int> neighbors = graph.GetNeighbors(pair.Key);
                //        neighbors.Add(pair.Key);
                //        var cols = (from n in colorizedGraph where neighbors.Exists(t => t == n.Key) select n.Value).Distinct().ToList<int>();
                //        if (cols.Count() >= Bound && cols.Count() >= globalClick.Count())
                //        {
                //            clique.Add(new List<int>());
                //            List<int> cur = new List<int>();
                //            RecursiveSearch(pair.Key, ref cur, ref neighbors, graph);
                //            clique[cntr] = cur;
                //            cntr++;
                //        }
                //}
                TimeSpan time = (DateTime.Now - startTime);
                Console.WriteLine("Time to find " + time);
                Console.WriteLine(globalClick.Count());
                Console.WriteLine(String.Join(" ", globalClick));
                WriteResults(time, globalClick, false);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("Fatal: " + ex.Message);
                Console.WriteLine(ex.StackTrace);
                Console.ReadKey();
            }
        }