Pochodzenie: Rozwi¸azanie:
VIII Olimpiada Informatyczna comm.cpp
W parlamencie Demokratycznej Republiki Bajtocji, zgodnie z Bardzo Ważn¸a Ustaw¸a, należy ukonstytuować Komisję Poselsk¸a do Spraw Spokoju Publicznego. Niestety sprawę utrudnia fakt, iż niektórzy posłowie wzajemnie się nie lubi¸a.
Komisja musi spełniać następuj¸ace warunki:
każda partia ma dokładnie jednego reprezentanta w Komisji,
jeśli dwaj posłowie się nie lubi¸a, to nie mog¸a jednocześnie być w Komisji.
Każda partia ma w parlamencie dokładnie dwóch posłów. Wszyscy posłowie s¸a ponumerowani liczbami od 1 do 2n. Posłowie o numerach 2i − 1 i 2i należ¸a do partii o numerze i.
Zadanie
Napisz program, który:
wczyta liczbę partii oraz pary posłów, którzy się wzajemnie nie lubi¸a,
wyznaczy skład Komisji, lub stwierdzi, że nie da się jej ukonstytuować,
wypisze wynik
Wejście
W pierwszym wierszu wejścia znajduj¸a się dwie nieujemne liczby całkowite n i m. Liczba n, spełniaj¸aca warunki 1 ¬ n ¬ 8 000, oznacza liczbę partii. Liczba m, spełniaj¸aca warunki 0 ¬ m ¬ 20 000, oznacza liczbę par nielubi¸acych się posłów. W każdym z kolejnych m wier-szy zapisana jest para liczb naturalnych a i b, 1 ¬ a 6= b ¬ 2n, oddzielonych pojedynczym odstępem. Oznacza ona, że posłowie o numerach a i b wzajemnie się nie lubi¸a.
Wyjście
W pierwszym i jedynym wierszu wyjścia powinno znaleźć się pojedyncze słowo NIE, jeśli utworzenie Komisji nie jest możliwe. W przypadku, gdy utworzenie Komisji jest możliwe, pro-gram powinien wypisać n liczb całkowitych z przedziału od 1 do 2n, zapisanych w kolejności rosn¸acej i oznaczaj¸acych numery posłów zasiadaj¸acych w Komisji. Każda z tych liczb powin-na zostać zapisapowin-na w osobnym wierszu. Jeśli Komisję możpowin-na utworzyć powin-na wiele sposobów, Twój program może wypisać dowolny z nich.
Przykład
Dla następuj¸acego wejścia:
3 2 1 3 2 4
Poprawnym rozwi¸azaniem jest:
1 4 6
Ćwiczenia
Proste Średnie Trudne
acm.uva.es - zadanie 124 acm.uva.es - zadanie 200 acm.uva.es - zadanie 10319 acm.uva.es - zadanie 10305 acm.sgu.ru - zadanie 230 spoj.sphere.pl - zadanie 44
spoj.sphere.pl - zadanie 70
2.6. Acykliczność
Maj¸ac dany graf G = (V, E) (skierowany b¸adź nieskierowany), można zadać pytanie, czy jest on acykliczny. Acykliczność grafu jest poż¸adan¸a własności¸a w wielu algorytmach.
Przykładowo, wyznaczanie topologicznego porz¸adku wierzchołków grafu skierowanego jest możliwe pod warunkiem, że graf, dla którego wyznaczany jest ten porz¸adek, jest acykliczny.
Opisany w poprzednim rozdziale algorytm zakłada prawdziwość tego faktu i nie sprawdza acykliczności grafu.
W przypadku grafów skierowanych, stosunkowo łatwo można Literatura [WDA] - 5.4 zmodyfikować algorytm służ¸acy do sortowania topologicznego
gra-fu, wzbogacaj¸ac go o dodatkowy test na acykliczność. Wystarczy pod koniec algorytmu sprawdzić, czy wszystkie krawędzie
prowa-dz¸a od wierzchołków znajduj¸acych się wcześniej, do wierzchołków znajduj¸acych się później w porz¸adku topologicznym. Implementacja tej metodologii jest zrealizowana w funkcji bool Graph<V,E>::AcyclicD() — do działania wymaga ona zaimplementowania funkcji void Graph<V,E>::TopoSort(), a zatem wykorzystuje również dodatkowe pole int t wierz-chołków. Implementacja tej funkcji znajduje się na listingu 2.21.
Listing 2.21: Implementacja funkcji bool Graph<V,E>::AcyclicD() // Funkcja sprawdzająca, czy dany graf skierowany jest acykliczny
1 bool AcyclicD() {
// Wyznacz sortowanie topologiczne 2 TopoSort();
// Dla każdej krawędzi w grafie sprawdź, czy prowadzi ona od wierzchołka // wcześniejszego do wierzchołka późniejszego w porządku topologicznym 3 FOREACH(it, g) FOREACH(it2, *it) if (it->t >= g[it2->v].t) return false;
4 return true;
5 }
Algorytm realizowany przez funkcję bool Graph<V,E>::AcyclicD()nie działa prawidłowo w przypadku grafów nieskierowanych — reprezentacja krawędzi (u, v) w takich grafach składa się z dwóch krawędzi skierowanych: (u, v), oraz (v, u). W podejściu realizowanym przez funkcję bool Graph<V,E>::AcyclicD(), każdy graf nieskierowany z co najmniej jedn¸a krawędzi¸a uważany jest za zawieraj¸acy cykl.
Dla grafów acyklicznych potrzebny jest inny algorytm. Funkcja bool Graph<V,E>::
AcyclicU(), której kod źródłowy został przedstawiony na listingu 2.22, jest implementacj¸a pomysłu działaj¸acego właśnie dla takich grafów. Wykonuje ona algorytm DFS dla wszyst-kich wierzchołków w grafie i w momencie powtórnego wejścia do tego samego wierzchołka stwierdza, że zawiera on cykl. Problem z reprezentacj¸a krawędzi nieskierowanych w postaci pary krawędzi skierowanych został rozwi¸azany poprzez nieprzetwarzanie krawędzi, po której algorytm wszedł do wierzchołka. Funkcja bool Graph<V,E>::AcyclicU() traktuje każd¸a pętlę oraz multikrawędzie jako cykl.
0
5 3 4 1 2
0
5 3 4 1 2
(a) (b)
Rysunek 2.6: (a) Nieskierowany graf acykliczny (b) Skierowany graf zawieraj¸acy cykl 5 → 4 → 0 → 5
Listing 2.22: Implementacja funkcji bool Graph<V,E>::AcyclicU() // Wskaźnik na tablicę służącą do odznaczania wierzchołków odwiedzonych 01 bool*vis;
// Zmienna, w której umieszczany jest wynik 02 boolacyc;
// Funkcja przeszukująca poddrzewo wierzchołka v w celu znalezienia cyklu 03 void AcDfs(intv, Ed * p) {
// Jeśli wierzchołek nie był jeszcze odwiedzony...
04 if (!vis[v]) { 05 vis[v] = 1;
// Przetwórz jego wszystkie krawędzie za wyjątkiem tej, po której przyszedłeś // od ojca
06 FOREACH(it, g[v]) if (&(*it) != p) AcDfs(it->v, &g[it->v][it->rev]);
07 } else acyc = 0;
08}
// Funkcja sprawdzająca, czy graf jest acykliczny - działa prawidłowo dla grafów // nieskierowanych
09 boolAcyclicU() {
// Inicjalizacja zmiennych 10 acyc = 1;
11 vis = new bool[SIZE(g)];
12 REP(x, SIZE(g)) vis[x] = 0;
// Dla każdego wierzchołka w grafie dokonaj przeszukiwania 13 REP(x, SIZE(g)) if (!vis[x]) AcDfs(x, 0);
14 delete[]vis;
15 return acyc;
16}
Złożoność czasowa obu przedstawionych w tym rozdziale funkcji to O(n + m). Tak samo jak w przypadku funkcji przedstawionych w poprzednich rozdziałach, implementacja jest pewn¸a modyfikacj¸a algorytmu DFS, która przetwarza każdy wierzchołek, oraz każd¸a krawędź grafu dokładnie raz. Dla grafu, przedstawionego na rysunku 2.6.a, funkcja boolGraph<V,E>
::AcyclicU()zwróci fałsz, natomiast funkcja bool Graph<V,E>::AcyclicD()dla grafu z rysunku 2.6.b — prawdę.