https://pl.spoj.com/problems/PTWPZ078
Skrócony opis problemu:
Mamy liczby n i m (n,m \le 10000) oznaczające odpowiednio ilość wierzchołków i krawędzi w digrafie oraz liczbę t (t<21) i t liczb oznaczających wierzchołki specjalne. Mamy wypisać z ilu wierzchołków (niekoniecznie zwykłych) da się dojść do wszystkich wierzchołków specjalnych.
Podejście naiwne:
Możemy dla każdego wierzchołka przechodzić graf zaczynając od niego (obojętnie czy BFSem czy DFSem) i sprawdzać do ilu wierzchołków specjalnych dojdzie. Jeśli dojdzie do t takich wierzchołków, to inkrementujemy nasz wynik.
Złożoność: O\left(n^2\right), bo dla n wierzchołków przechodzimy graf, a przechodzenia ma złożoność O(n+m), a jako że m=n, to O(n).
Podejście sprytne:
Poszukujemy ścieżek między danym wierzchołkiem specjalnym x, a pozostałymi wierzchołkami. Czemu więc nie zmienić kierunku tej ścieżki? Przechodźmy zatem graf, ale wychodząc tylko z wierzchołków specjalnych i poruszając się po grafie G', w którym krawędzie a \rightarrow b zamienimy na krawędzie b \rightarrow a. Wykonujemy zatem t przeszukiwań grafu i w każdym inkrementujemy ilość wierzchołków specjalnych odwiedzonych przez wierzchołek y, jeśli z wierzchołka specjalnego x dojdziemy do y.
Złożoność: O(t \cdot n), bo mamy t przeszukiwań o złożoności O(n).
Ostateczny algorytm:
vector<int> tab[10009]; int ile[10009]; bool czy[10009]; void dfs(int v) { ++ile[v]; czy[v] = 1; for(int i = 0; i < tab[v].size(); ++i) if(!czy[tab[v][i]]) dfs(tab[v][i]); } int main() { int t, n, m, i, j, a, b, k[29]; scanf("%d%d", &n, &m); while(m--) scanf("%d%d", &a, &b), tab[b].push_back(a); scanf("%d", &t); for(i = 0; i < t; ++i) scanf("%d", &k[i]); for(i = 1; i <= n; ++i) ile[i] = 0; for(i = 0; i < t; ++i) { for(j = 1; j <= n; ++j) czy[j] = 0; dfs(k[i]); } for(a = 0, i = 1; i <= n; ++i) a += ile[i]>=t; printf("%d\n", a); }
Brak komentarzy:
Prześlij komentarz