czwartek, 7 marca 2013

4651. PTwPZ Zamek [PTWPZ078]

Zadanie:
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