} // GetNodeToDrop static List <int> MakeOneMissing(MaxCliqueGraph graph, List <int> clique) { int count; List <int> result = new List <int>(); for (int i = 0; i < graph.NumberNodes; ++i) { if (graph.NumberNeighbors(i) < clique.Count - 1) { continue; } if (clique.BinarySearch(i) >= 0) { continue; } count = 0; 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); }
static bool FormsALargerClique(MaxCliqueGraph graph, List <int> clique, int node) { for (int i = 0; i < clique.Count; ++i) { if (graph.AreAdjacent(clique[i], node) == false) { return(false); } } return(true); }
static List <int> MakePossibleAdd(MaxCliqueGraph graph, List <int> clique) { List <int> result = new List <int>(); for (int i = 0; i < graph.NumberNodes; ++i) { if (FormsALargerClique(graph, clique, i) == true) { result.Add(i); } } return(result); }
static int UpdateProhibitPeriod(MaxCliqueGraph graph, List <int> clique, int bestSize, Dictionary <int, CliqueInfo> history, int time, int prohibitPeriod, ref int timeProhibitChanged) { int result = prohibitPeriod; CliqueInfo cliqueInfo = new CliqueInfo(clique, time); if (history.ContainsKey(cliqueInfo.GetHashCode())) { CliqueInfo ci = history[cliqueInfo.GetHashCode()]; int intervalSinceLastVisit = time - ci.LastSeen; ci.LastSeen = time; if (intervalSinceLastVisit < 2 * graph.NumberNodes - 1) { timeProhibitChanged = time; if (prohibitPeriod + 1 < 2 * bestSize) { return(prohibitPeriod + 1); } else { return(2 * bestSize); } } } else { history.Add(cliqueInfo.GetHashCode(), cliqueInfo); } if (time - timeProhibitChanged > 10 * bestSize) { timeProhibitChanged = time; if (prohibitPeriod - 1 > 1) { return(prohibitPeriod - 1); } else { return(1); } } else { return(result); // нет изменений } } // UpdateProhibitTime
static int GetNodeToDrop(MaxCliqueGraph graph, List <int> clique, List <int> oneMissing) { if (clique.Count == 1) { return(clique[0]); } List <int> cliqueCountNotAdjacent = new List <int>(clique.Count); 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; } } cliqueCountNotAdjacent.Add(countNotAdjacent); if (countNotAdjacent > maxCount) { maxCount = countNotAdjacent; } } List <int> candidates = new List <int>(); for (int i = 0; i < clique.Count; ++i) { if (cliqueCountNotAdjacent[i] == maxCount) { candidates.Add(clique[i]); } } if (candidates.Count == 1) { return(candidates[0]); } return(candidates[random.Next(0, candidates.Count)]); } // GetNodeToDrop
static int GetNodeToAdd(MaxCliqueGraph graph, List <int> allowedAdd, List <int> possibleAdd) { if (allowedAdd.Count == 1) { return(allowedAdd[0]); } List <int> allowedAddDegree = new List <int>(possibleAdd.Count); int maxDegree = 0; for (int i = 0; i < allowedAdd.Count; ++i) { int currNode = allowedAdd[i]; int degreeOfCurrentNode = 0; for (int j = 0; j < possibleAdd.Count; ++j) { int otherNode = possibleAdd[j]; if (graph.AreAdjacent(currNode, otherNode) == true) { ++degreeOfCurrentNode; } } allowedAddDegree.Add(degreeOfCurrentNode); if (degreeOfCurrentNode > maxDegree) { maxDegree = degreeOfCurrentNode; } } List <int> candidates = new List <int>(); for (int i = 0; i < allowedAdd.Count; ++i) { if (allowedAddDegree[i] == maxDegree) { candidates.Add(possibleAdd[i]); } } if (candidates.Count == 1) { return(candidates[0]); } return(candidates[random.Next(0, candidates.Count)]); }
static void Main(string[] args) { try { Console.WriteLine("\nBegin greedy maximum clique demo\n"); Console.WriteLine("\nBegin tabu algorithm maximum clique demo\n"); string graphFile = "..\\..\\DimacsGraph.clq"; //string graphFile = "DimacsGraph.clq"; MaxCliqueGraph.ValidateGraphFile(graphFile, FileFormat.DIMACS); //"DIMACS" MaxCliqueGraph graph = new MaxCliqueGraph(graphFile, FileFormat.DIMACS); graph.ValidateGraph(); Console.WriteLine("Loading graph into memory"); Console.WriteLine("Graph loaded and validated\n"); int maxTime = 50; // В настоящей задаче о максимальной клике maxTime обычно находится в диапазоне от 1000 до 100 000. int targetCliqueSize = graph.NumberNodes; List <int> maxClique = FindMaxClique(graph, maxTime, targetCliqueSize); Console.WriteLine("\nMaximum time reached"); Console.WriteLine("\nSize of best clique found = " + maxClique.Count); Console.WriteLine("\nBest clique found:"); Console.WriteLine(ListAsString(maxClique)); Console.WriteLine("\nEnd greedy maximum clique demo\n"); Console.WriteLine(graph.ToString()); Console.WriteLine("\nAre nodes 5 and 8 adjacent? " + graph.AreAdjacent(5, 8)); Console.WriteLine("Number neighbors of node 4 = " + graph.NumberNeighbors(4)); WriteFile(ListAsString(maxClique), "output.txt"); string outputGraphFile = "..\\..\\output.txt"; graph.SaveTxtFormatGraph(outputGraphFile); } catch (Exception ex) { Console.WriteLine("Fatal: " + ex.Message); } } // Main
static List <int> FindMaxClique(MaxCliqueGraph graph, int maxTime, int targetCliqueSize) { List <int> clique = new List <int>(); random = new Random(1); int time = 0; int timeBestCliqueFound = 0; //timeBestClique int timeLastRestart = 0; //timeRestart int nodeToAdd = -1; int nodeToDrop = -1; int prohibitPeriod = 1; int timeProhibitChanged = 0; int[] lastMoved = new int[graph.NumberNodes]; for (int i = 0; i < lastMoved.Length; ++i) { lastMoved[i] = int.MinValue; } Dictionary <int, CliqueInfo> history = new Dictionary <int, CliqueInfo>(); int randomNode = random.Next(0, graph.NumberNodes); Console.WriteLine("Adding node " + randomNode); clique.Add(randomNode); List <int> bestClique = new List <int>(); bestClique.AddRange(clique); int bestSize = bestClique.Count; timeBestCliqueFound = time; //int timeBestCliqueFound = 0; //int timeLastRestart = 0; List <int> possibleAdd = MakePossibleAdd(graph, clique); List <int> oneMissing = MakeOneMissing(graph, clique); while (time < maxTime && bestSize < targetCliqueSize) { ++time; bool cliqueChanged = false; ValidateClique(clique, possibleAdd, oneMissing); if (possibleAdd.Count > 0) { List <int> allowedAdd = SelectAllowedNodes(possibleAdd, time, prohibitPeriod, lastMoved); if (allowedAdd.Count > 0) { nodeToAdd = GetNodeToAdd(graph, allowedAdd, possibleAdd); Console.WriteLine("Adding node " + nodeToAdd); clique.Add(nodeToAdd); lastMoved[nodeToAdd] = time; clique.Sort(); cliqueChanged = true; if (clique.Count > bestSize) { bestSize = clique.Count; bestClique.Clear(); bestClique.AddRange(clique); timeBestCliqueFound = time; } } } // добавление if (cliqueChanged == false) { if (clique.Count > 0) { List <int> allowedInClique = SelectAllowedNodes(clique, time, prohibitPeriod, lastMoved); if (allowedInClique.Count > 0) { nodeToDrop = GetNodeToDrop(graph, clique, oneMissing); Console.WriteLine("Dropping node " + nodeToDrop); clique.Remove(nodeToDrop); lastMoved[nodeToDrop] = time; clique.Sort(); cliqueChanged = true; } } } // удаление if (cliqueChanged == false) // если невозможно добавить или удалить разрешенный узел { if (clique.Count > 0) { nodeToDrop = clique[random.Next(0, clique.Count)]; clique.Remove(nodeToDrop); lastMoved[nodeToDrop] = time; clique.Sort(); cliqueChanged = true; } } int restart = 2 * bestSize; // 100 if (time - timeBestCliqueFound > restart && time - timeLastRestart > restart) { Console.WriteLine("\nRestarting\n"); timeLastRestart = time; prohibitPeriod = 1; timeProhibitChanged = time; history.Clear(); int seedNode = -1; List <int> temp = new List <int>(); for (int i = 0; i < lastMoved.Length; ++i) { if (lastMoved[i] == int.MinValue) { temp.Add(i); } } if (temp.Count > 0) { seedNode = temp[random.Next(0, temp.Count)]; } else { seedNode = random.Next(0, graph.NumberNodes); } clique.Clear(); clique.Add(seedNode); Console.WriteLine("Adding node " + seedNode); } // перезапуск possibleAdd = MakePossibleAdd(graph, clique); // Альтернатива — поддерживать вспомогательные структуры данных oneMissing = MakeOneMissing(graph, clique); // и обновлять эти два списка вместо повторного их создания с нуля. prohibitPeriod = UpdateProhibitPeriod(graph, clique, bestSize, history, time, prohibitPeriod, ref timeProhibitChanged); } // основной цикл обработки return(bestClique); }