U mreži, računari su povezani kablovima kroz koje signal može da putuje samo u jednom smeru. Računari su povezani tako da signal poslat sa nekog računara ne može da se vrati do istog računara. Za datu mrežu računara, početni i krajnji računar, odrediti broj puteva od početnog do krajnjeg računara.
Sa standardnog ulaza se unosi broj računara \(n\) i broj kablova \(m\). Za svako \(j=1,\ldots,m\) u zasebnoj liniji unosi se početak \(u_j\) i kraj \(v_j\) usmerenog kabla. Nakon toga, unose se dva računara \(s\) i \(t\).
Napomena: Pretpostaviti da je \(t\) dostižan iz \(s\), tj. da postoji put od \(s\) do \(t\).
Na standardni izlaz ispisati broj mogućih puteva puteva od \(s\) do \(t\).
5 5 0 1 1 3 1 4 2 1 3 4 0 4
2
Problem možemo svesti na pronalazak broja prostih puteva od čvora \(s\) do čvora \(t\) u usmerenom acikličnom grafu \(G = (V, E)\). Čvorovi grafa će predstavljati računare, dok će grane predstavljati usmerene kablove između računara.
Kako je graf usmeren i acikličan topološkim sortiranjem dobijamo poredak čvorova \(v_1, v_2, \ldots, v_n\). Kako postoji put iz \(s\) do \(t\), onda je \(s\) sigurno pre \(t\) u topološkom poredku. Tada su \(s = v_i, v_{i+1}, \ldots, v_{j-1}, v_j = t\) čvorovi kroz koje može prolaziti neki od traženih puteva, tj. sigurno znamo da ostale čvorove ne treba razmatrati (\(v_1, \ldots, v_{i - 1}\) nisu dostižni iz \(s\), a \(t\) nije dostižan iz \(v_{j + 1}, \ldots, v_n\)). Sada možemo definisati rekurzivnu funkciju \(f(u)\) koja će računati broj prostih puteva iz \(u\) do \(t\): \[\begin{align*} f(u) &= 1, &\qquad u = v_j = t \\ f(u) &= 0, &\qquad u \in \{ v_{j + 1}, \ldots, v_n \} \\ f(u) &= \sum_{v \in \{ v_i, \ldots, v_j \} \\ (u, v) \in E} f(v) &\qquad u \in \{ v_i, \ldots, v_{j - 1} \} \\ \end{align*}\]
Kako je funkcija \(f\) definisana rekurzivno, i pri tome je moguće višestruko pozivanje funkcije \(f\) nad istim čvorom \(u\), složenost izračunavanja funkcije \(f\) možemo poboljšati tehnikom memoizacije, i tada će ona biti \(O(|V| + |E|)\). Kako je topološko sortiranje složenosti \(O(|V| + |E|)\), ukupna složenost algoritma je \(O(|V| + |E|)\).
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#include <limits>
using namespace std;
class Graph {
private:
int broj_cvorova;
int>> lista_suseda;
vector<vector<bool> posecen;
vector<int> topoloski_poredak;
vector<int, int>> dodate_grane;
vector<pair<// Stek koji ce nam je potreban za algoritam topoloskog sortiranja zasnovan na DFS pretrazi grafa
int> stek;
stack<
public:
int broj_cvorova) {
Graph(this->broj_cvorova = broj_cvorova;
lista_suseda.resize(broj_cvorova);false);
posecen.resize(broj_cvorova,
}
void dodaj_granu(int u, int v) {
lista_suseda[u].push_back(v);
}
void DFS_topolosko_sortiranje(int u) {
true;
posecen[u] =
for (int v : lista_suseda[u]) {
if (!posecen[v]) {
DFS_topolosko_sortiranje(v);
}
}
// TEK NAKON STO SMO OBISLI SVE NJEGOVE SUSEDE dodajemo element na stek, kako se on nalazi vise na steku bice i
// ranije uklonjen sa steka pa ce se naci ranije u topoloskom poretku a svi cvorovi koji "zavise" od njega ce se
// ukloniti kasnije i samim tim ce se naci kasnije u topoloskom poretku
stek.push(u);
}
void topolosko_sortiranje() {
for (int i = 0; i < broj_cvorova; i++) {
if (!posecen[i]) {
DFS_topolosko_sortiranje(i);
}
}
int cvor;
while (!stek.empty()) {
cvor = stek.top();
stek.pop();
topoloski_poredak.push_back(cvor);
}
}
int num_paths_aid(const int u, const int t, const vector<int> &pi, vector<int> &memo) {
if (memo[u] != -1) {
return memo[u];
}
if (pi[u] == pi[t]) {
return memo[u] = 1;
}
if (pi[u] > pi[t]) {
return memo[u] = 0;
}
0;
memo[u] = for (int v : lista_suseda[u]) {
if (pi[v] <= pi[t]) {
memo[u] += num_paths_aid(v, t, pi, memo);
}
}return memo[u];
}
int num_paths(int s, int t) {
topolosko_sortiranje();
int> pi(broj_cvorova);
vector<for (int i = 0; i < topoloski_poredak.size(); i++) {
pi[topoloski_poredak[i]] = i;
}
int> memo(broj_cvorova, -1);
vector<return num_paths_aid(s, t, pi, memo);
}
};
int main ()
{int n, m;
cin >> n >> m;
new Graph(n);
Graph *G =
int u, v;
for (int i = 0; i < m; i++) {
cin >> u >> v;
G->dodaj_granu(u, v);
}
int s, t;
cin >> s >> t;
cout << G->num_paths(s, t) << endl;
return 0;
}