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