#include <bits/stdc++.h>
using namespace std;
class Graf {
private:
int nr_noduri;
int nr_muchii;
vector<vector <int>> lista_vecini;
public:
Graf();
Graf(int nr_noduri, int nr_muchii);
~Graf();
vector<vector<int>> getlista_vecini();
void graf_neorientat(istream &fis_sursa);
void graf_orientat(istream &fis_sursa);
void graf_orientat_DFS(istream &fis_sursa);
void DFS(int nod, vector<bool> &vizitat);
int comp_conexe();
void BFS(int nod, ostream &fis_destinatie);
void hakimi(int noduri, vector<int> &lista, ostream &fis_destinatie);
int DFS_sortaret(queue<int> &ordine);
void DFS_biconex(int nod, int nivel_actual, vector<int> &nivel, vector<int> &nivel_minim, vector<bool> &vizitat, deque<int> &d, vector<vector<int>> &subgraf_biconex, int &nr_biconexe);
int disjoint_gasit(int a, vector<int> &v);
void disjoint_uneste(int a, int b, vector<int> &v, vector<int> &rang);
void dijkstra(vector<pair<int, int>> &muchii, vector<int> &distante, int x);
int grupa(int grade[100005],int i);
void reuniune(int grade[100005], int i, int j);
void apm(int st[100005], int dr[100005], int costuri[100005], int indici[100005], vector<int> &ordine_muchii, int grade[100005], int &cost);
void royfloyd(int a[105][105]);
void darb(int start, int contor[100005], int vizitat[100005], int &capat, int &diametru);
};
Graf::Graf()
{
nr_noduri = 0;
nr_muchii = 0;
}
Graf::Graf(int nr_noduri_fis, int nr_muchii_fis)
{
vector<int> v(1,-1);
nr_noduri = nr_noduri_fis;
nr_muchii = nr_muchii_fis;
for(int i = 0; i <= nr_noduri; i++)
lista_vecini.push_back(v);
}
Graf::~Graf()
{
nr_noduri = 0;
nr_muchii = 0;
lista_vecini.clear();
}
vector<vector<int>> Graf::getlista_vecini()
{
return lista_vecini;
}
void Graf::graf_neorientat(istream &fis_sursa)
{
int a, b;
if(nr_muchii)
for(int i = 1; i <= nr_muchii; i++)
{
fis_sursa >> a >> b;
lista_vecini[a].push_back(b);
lista_vecini[b].push_back(a);
}
else
while(!fis_sursa.eof())
{
fis_sursa >> a >> b;
lista_vecini[a].push_back(b);
lista_vecini[b].push_back(a);
}
}
void Graf::graf_orientat(istream &fis_sursa)
{
int a, b;
for(int i = 1; i <= nr_muchii; i++)
{
fis_sursa >> a >> b;
lista_vecini[a-1].push_back(b-1);
}
}
void Graf::graf_orientat_DFS(istream &fis_sursa)
{
int a, b;
for(int i = 1; i <= nr_muchii; i++)
{
fis_sursa >> a >> b;
lista_vecini[a].push_back(b);
}
}
void Graf::DFS(int nod, vector<bool> &viz)
{
viz[nod] = 1;
for(int i = 1; i < lista_vecini[nod].size(); i++)
if(viz[lista_vecini[nod][i]] == 0)
DFS(lista_vecini[nod][i], viz);
}
int Graf::comp_conexe()
{
int nr = 0;
vector<bool> viz(nr_noduri + 1, 0);
for(int i = 1; i <= nr_noduri; i++)
if(!viz[i])
{
nr++;
DFS(i, viz);
}
return nr;
}
void Graf::BFS(int nod, ostream &fis_destinatie)
{
int a;
queue<int> coada;
vector<int> dist(nr_noduri, -1);
dist[nod-1] = 0;
coada.push(nod-1);
while(!coada.empty())
{
a = coada.front();
coada.pop();
for(auto& i: lista_vecini[a])
if(dist[i] == -1)
{
dist[i] = dist[a] + 1;
coada.push(i);
}
}
for(int i = 0; i < nr_noduri; i++)
fis_destinatie << dist[i] << " ";
}
void Graf::hakimi(int noduri, vector<int> &lista, ostream &fis_destinatie)
{
int cond = 0;
while(cond == 0)
{
sort(lista.begin(), lista.end(), greater<>());
if ( lista[0] == 0)
cond = 1;
cout<<lista[0]<<" ";
int aux = lista[0];
lista.erase(lista.begin() + 0);
if(aux > lista.size())
cond = -1;
for(int i = 0; i < aux; i++)
{
lista[i]--;
if(lista[i] < 0)
cond = -1;
}
}
if(cond == 1)
fis_destinatie << "DA\n";
else
fis_destinatie << "NU\n";
}
int Graf::DFS_sortaret(queue<int> &lista)
{
queue<int> nod_grade;
vector<int> grade_interne(100005, 0);
for(int i = 1; i <= nr_noduri; i++)
for(int j = 1; j < lista_vecini[i].size(); j++)
grade_interne[lista_vecini[i][j]] += 1;
for(int i = 1; i <= nr_noduri; i++)
if(grade_interne[i] == 0)
nod_grade.push(i);
while(!nod_grade.empty())
{
int aux = nod_grade.front();
nod_grade.pop();
lista.push(aux);
for(int i = 1; i < lista_vecini[aux].size(); i++)
{
grade_interne[lista_vecini[aux][i]] --;
if(grade_interne[lista_vecini[aux][i]] == 0)
nod_grade.push(lista_vecini[aux][i]);
}
}
if(nr_noduri == lista.size())
return 1;
else
return 0;
}
/*
void Graf::DFS_biconex(int tata,int nod, vector<int> &nivel, vector<int> &nivel_minim, vector<bool> &vizitat, deque<int> &d, vector<vector<int>> &subgraf_biconex, int &nr_biconexe)
{
vizitat[nod] = 1;
nivel_minim[nod] = nivel[nod];
d.push_back(nod); // marchez nodul ca vizitat si il pun in deque
for(int i = 0; i < lista_vecini[nod].size(); i++)
{
int vecin = lista_vecini[nod][i];
if(vecin == tata)
continue;
if(vizitat[vecin])
{
nivel_minim[nod] = min(nivel_minim[nod], nivel[vecin]); // daca vecinul a fost vizitat, actualizez nivelul minim al nodului
}
nivel[vecin] = nivel[nod] + 1;
DFS_biconex(nod, vecin, nivel, nivel_minim, vizitat, d, subgraf_biconex, nr_biconexe);
nivel_minim[nod] = min(nivel_minim[nod], nivel_minim[vecin]); // reactualizez nivelul minim al nodului
if(nivel_minim[vecin] >= nivel[nod])
{
nr_biconexe++; // am gasit o componenta biconexa
int aux;
do
{
subgraf_biconex[nr_biconexe].push_back(d.back());
aux = d.back();
d.pop_back();
}while(!d.empty() && aux != vecin); // adaug elementele componentei in vectorul cu solutii
subgraf_biconex[nr_biconexe].push_back(nod);
}
}
}
*/
int Graf::disjoint_gasit(int a, vector<int> &v)
{
int i, aux;
for (i = a; v[i] != i; i = v[i]); // caut in arbore un nod ce pointeaza la el insusi
for(; v[a] != a;) // realizez compresia drumurilor
{
aux = v[a];
v[a] = i;
a = aux;
}
return i;
}
void Graf::disjoint_uneste(int a, int b, vector<int> &v, vector<int> &rang)
{
if(rang[a] > rang[b]) // atasez multimea cu rang mai mic la cea cu rang mai mare
v[b] = a;
else v[a] = b;
if(rang[a] == rang[b]) // maresc rangul multimii pe care vreau sa o adaug recent in caz de egalitate
rang[b]++;
}
/* void Graf::dijkstra(vector<pair<int, int>> &muchii, vector<int> &distante, int x)
{
distante[1] = 0;
set<pair<int, int>> s;
s.insert(make_pair(0, 1)); //introduc nodul 1
while(!s.empty()) // cat timp nu am parcurs toate nodurile la care pot ajunge
{
int nod = s.begin()->second;
int d = s.begin()->first;
s.erase(s.begin());
for(vector<pair<int, int>>::iterator it = muchii[nod].begin(); it != muchii[nod].end(); ++it) // ma plimb in muchiile care incep cu nodul respectiv
{
int capat = it->first;
int cost = it->second;
if(distante[capat] > distante[nod] + cost) // verific daca distanta este minima
{
if(distante[capat] != x)
s.erase(s.find(make_pair(distante[capat], capat))); // o sterg daca nu distanta nu este val initiala
distante[capat] = distante[nod] + cost;
s.insert(make_pair(distante[capat], capat)); // calculez distanta minima si o adaug in set
}
}
}
} */
int Graf::grupa(int grade[100005],int i)
{
if(grade[i] == i) return i;
grade[i] = grupa(grade, grade[i]);
return grade[i];
}
void Graf::reuniune(int grade[100005], int i, int j)
{
grade[grupa(grade, i)] = grupa(grade, j);
}
void Graf::apm(int st[100005], int dr[100005], int costuri[100005], int indici[100005], vector<int> &ordine_muchii, int grade[100005], int &cost)
{
for(int i = 1; i <= nr_muchii; ++i)
if(grupa(grade, st[indici[i]]) != grupa(grade, dr[indici[i]]))
{
cost += costuri[indici[i]];
reuniune(grade, st[indici[i]], dr[indici[i]]);
ordine_muchii.push_back(indici[i]);
}
}
void Graf::royfloyd(int a[105][105])
{
for(int k = 1; k <= nr_noduri; k++)
for(int i = 1; i <= nr_noduri; i++)
for(int j = 1; j <= nr_noduri; j++)
if(a[i][k] && a[k][j] && (a[i][j] > a[i][k] + a[k][j] || !a[i][j]) && i != j)
a[i][j] = a[i][k] + a[k][j];
}
void Graf::darb(int start, int contor[1000005], int vizitat[1000005], int &capat, int &diametru)
{
queue<int> coada;
memset(contor, 0, 1000005);
memset(vizitat, 0, 1000005);
coada.push(start);
contor[start] = 1;
vizitat[start] = 1;
while(!coada.empty())
{
int el = coada.front();
for(int i = 0; i < lista_vecini[el].size(); i++)
{
if(vizitat[lista_vecini[el][i]] == 0)
{
coada.push(lista_vecini[el][i]);
contor[lista_vecini[el][i]] = contor[el] + 1;
vizitat[lista_vecini[el][i]] = 1;
diametru = contor[lista_vecini[el][i]];
capat = lista_vecini[el][i];
}
}
coada.pop();
}
}
void pb1_BFS()
{
ifstream f("bfs.in");
ofstream g("bfs.out");
int N, M, S;
f >> N >> M >> S;
Graf graf(N, M);
graf.graf_orientat(f);
graf.BFS(S, g);
f.close();
g.close();
}
void pb2_DFS()
{
ifstream f("dfs.in");
ofstream g("dfs.out");
int N, M;
f >> N >> M;
Graf graf(N, M);
graf.graf_neorientat(f);
g << graf.comp_conexe();
f.close();
g.close();
}
void pb_hakimi()
{
ifstream f("hakimi.in");
ofstream g("hakimi.out");
int N;
vector<int> V(100005);
f >> N;
for(int i = 0; i < N; i++)
f >> V[i];
Graf graf(N, 0);
graf.hakimi(N, V, g);
f.close();
g.close();
}
void pb_sortaret()
{
ifstream f("sortaret.in");
ofstream g("sortaret.out");
int N, M, x;
vector<bool> viz(100005, 0);
queue<int> lista;
f >> N >> M;
Graf graf(N, M);
graf.graf_orientat_DFS(f);
x = graf.DFS_sortaret(lista);
if(x)
{
while(!lista.empty())
{
g << lista.front() <<" ";
lista.pop();
}
}
else
g << "Graful nu are o sortare topologica!";
f.close();
g.close();
}
/*
void biconex()
{
ifstream f("biconex.in");
ofstream g("biconex.out");
int N, M, nr_biconexe = 0;
vector<int> nivel(100005, 0);
vector<int> nivel_minim(100005, 0);
deque<int> d;
vector<bool> vizitat(100005, 0);
vector<vector<int>> subgraf_biconex(100005);
f >> N >> M;
Graf graf(N, M);
graf.graf_neorientat(f);
graf.DFS_biconex(0, 1, nivel, nivel_minim, vizitat, d, subgraf_biconex, nr_biconexe);
g << nr_biconexe << "\n";
for(int i = 1; i <= nr_biconexe; i++)
{
for(int j = 0; j < subgraf_biconex[i].size(); i++)
g << subgraf_biconex[i][j] << " ";
g << "\n";
}
f.close();
g.close();
}
*/
void pb_disjoint()
{
ifstream f("disjoint.in");
ofstream g("disjoint.out");
vector<int> v(100005);
vector<int> rang(100005);
int cod, a, b, N, M;
f >> N >> M;
Graf graf(N, 0);
for(int i = 1; i <= N; i++)
{
v[i] = i;
rang[i] = 1;
}
for(int i = 1; i <= M; i++)
{
f >> cod >> a >> b;
if (cod == 2)
{
if(graf.disjoint_gasit(a, v) == graf.disjoint_gasit(b, v)) //verifica daca am aceiasi radacina
g << "DA\n";
else
g << "NU\n";
}
else //unesc nodurile
{
graf.disjoint_uneste(graf.disjoint_gasit(a, v), graf.disjoint_gasit(b, v), v, rang);
}
}
}
/*
void pb_dijkstra()
{
ifstream f("dijkstra.in");
ofstream g("dijkstra.out");
vector<pair<int, int>> muchii(100005);
int x = 10000000;
vector<int> distante(100005, x);
int N, M, A, B, C;
f >> N >> M;
Graf graf(N,0);
for(int i = 0; i < M; i++)
{
f >> A >> B >> C;
muchii[A].push_back(make_pair(B, C));
}
return ;
graf.dijkstra(muchii, distante, x);
for(int i = 2; i <= N; i++)
{
if(distante[i] == x)
distante[i] = 0;
g << distante[i] << " ";
}
}
void pb_apm()
{
vector<int> ordine_muchii;
int N, M, cost;
int st[100005], dr[100005], costuri[100005], indici[100005], grade[100005];
ifstream f("apm.in");
ofstream g("apm.out");
f >> N >> M;
Graf graf(N, M);
for(int i = 1; i <= M; ++i)
{
f >> st[i] >> dr[i] >> costuri[i];
indici[i];
}
for(int i = 1; i <= N; ++i)
grade[i] = i;
sort(indici + 1; indici + M + 1, cmp(costuri));
graf.apm(st, dr, costuri, indici, ordine_muchii, grade, cost);
g << cost << "\n";
g << N-1 << "\n";
for(int i = 0; i < N-1; ++i)
g << st[ordine_muchii[i]] << " " << dr[ordine_muchii[i]] << "\n";
}
*/
void pb_royfloyd()
{
ifstream f("royfloyd.in");
ofstream g("royfloyd.out");
int a[105][105], n;
f >> n;
Graf graf(n, 0);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
f >> a[i][j];
graf.royfloyd(a);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
g << a[i][j] << " ";
g << "\n";
}
}
void pb_darb()
{
ifstream f("darb.in");
ofstream g("darb.out");
int contor[1000005], vizitat[1000005];
int N, M, nod_departat_initial , nod_departat_final , diametru;
f >> N ;
Graf graf(N, 0);
graf.graf_neorientat(f);
graf.darb(1, contor, vizitat, nod_departat_initial, diametru);
graf.darb(nod_departat_initial, contor, vizitat, nod_departat_final, diametru);
g << diametru;
}
int main() {
pb_darb();
return 0;
}