public bool CheckAndSet(HashSet<int>[] sets, bool Red, ref Colors colors, int position) { List<int> SetList = NodeSets[position]; foreach (int Set in SetList) { if (Red) // analogicznie jak w 2. { if (InfoSets[Set].Empty <= 0) throw new Exception("Nie ma miejsca a powinno"); if (InfoSets[Set].Empty > 1) continue; if (InfoSets[Set].Empty == 1) { if (InfoSets[Set].Blue == 0) return false; else continue; } } else { if (InfoSets[Set].Empty <= 0) throw new Exception("Nie ma miejsca a powinno"); if (InfoSets[Set].Empty > 1) // więcej niż 1 możemy dowolny continue; if (InfoSets[Set].Empty == 1) // 1 wolny { if (InfoSets[Set].Red == 0) return false; // 2. koloru nie ma nie dopuszczamy do tego else continue; // 2. kolor już jest } } } // kolorujemy element (w poszczególnych zbiorach) // wcześniej nie moglibyśmy tego zrobić bo np. kolorujemy i okazuje się, że w którymś nie da rady włożyć go // i jak odwrócić proces? if (Red) { foreach (int Set in SetList) { InfoSets[Set].Red++; InfoSets[Set].Empty--; } //colors[position] = 1; // tu odkomentować } else { foreach (int Set in SetList) { InfoSets[Set].Blue++; InfoSets[Set].Empty--; } //colors[position] = 2; // tu odkomentować } return true; }
public bool Split(List<HashSet<int>> sets, ref Colors colors) { if (sets == null) return true; if (sets.Count <= 0) { for (int i = 0; i < colors.n; i++) colors[i] = 1; return true; } //long LastTicks = DateTime.Now.Ticks; // wg. mnie czas jest dużo lepszym oszacowanie wydajności (zwłaszcza uśredniony dla losowych danych i wielu uruchomień) // Czasu nie oszukam HashSet<int>[] setsArr = sets.ToArray(); InitializeSets(setsArr, ref colors); int nSets = setsArr.Length; int nColors = colors.n; bool result = Iterate(setsArr, ref colors, 0); //Console.WriteLine("Ilosc ms {0}", (double)(DateTime.Now.Ticks - LastTicks) / 10000.0d); return result; }
public void InitializeSets(HashSet<int>[] sets, ref Colors colors) { int nSets = sets.Length; NodeSets = new List<int>[colors.n]; for (int i = 0; i < colors.n; i++) NodeSets[i] = new List<int>(); InfoSets = new set[nSets]; for (int i = 0; i < nSets; i++) { foreach (int El in sets[i]) NodeSets[El].Add(i); InfoSets[i].Blue = 0; InfoSets[i].Red = 0; // na początku nie oznaczyliśmy żadnych elementów na żaden kolor InfoSets[i].Empty = sets[i].Count; // na początku wszystkie są nie pokolorowane } }
public bool Iterate(HashSet<int>[] sets, ref Colors colors, int position) { if (sets == null) return false; if (sets.Length <= 0) { for (int i = 0; i < colors.n; i++) colors[i] = 1; return true; } if (position >= colors.n) // jeżeli doszło to znaleźliśmy rozwiązanie return true; // bo po 1. jest poprawny gdyż funkcja CheckAndSet pilnuje tego if (CheckAndSet(sets, true, ref colors, position)) // czy możemy go pokolorwać { // jeżeli tak to funkcja CheckAndSet koloruje bool result = Iterate(sets, ref colors, position + 1); UnSet(true, position); // odkolorowujemy if (result) { colors[position] = 1; // tu zakomentować return true; } } if (CheckAndSet(sets, false, ref colors, position)) { bool result = Iterate(sets, ref colors, position + 1); UnSet(false, position); if (result) { // fajnie w tej gałęźi znaleźliśmy colors[position] = 2; // tu zakomentować return true; } } // ta gałąź nic nie znalazła return false; }
private static void Test(int n, List<HashSet<int>> sets, bool expected) { bool res; Colors colors = new Colors(n); Solver sol = new Solver(n); Colors.ResetCounter(); long LastTicks = DateTime.Now.Ticks; res = sol.Split(sets, ref colors); Console.WriteLine("Zajęło : {0,2} ms", (double)(DateTime.Now.Ticks - LastTicks) / 10000.0d); Console.WriteLine("--------------------------------------"); Console.WriteLine("Test {0}\nJest {1}, powinno być {2}, wynik testu: {3}\nLiczba operacji: {4}", testnum++, res, expected, res==expected, Colors.OperationCounter); if (n <= 10) { for (int i = 0; i < n; ++i) Console.WriteLine("{0} {1}", i, colors[i]); } }