#include <bits/stdc++.h>
#include <iostream>
#include <fstream>
using namespace std;
vector<vector<int> >lista_ad_2;
ifstream fin("dfs.in");
ofstream gout("dfs.out");
class Graf{
private:
bool orientat;
int noduri;
vector< vector<int> > lista_ad;
vector< vector<int> > matrice;
vector< pair< pair <int, int>, int> > lista_muchii;
vector< vector<pair<int, int> > > lista_adiac;
priority_queue <pair<int, int>, vector <pair<int,int> >, greater <pair<int,int> > > coada;
vector<int> Dist;
vector< int > reprez;
vector< int > dim;
vector< pair<int, int> > rez;
int muchii = 0;
public:
Graf ();
Graf (int noduri,bool o);
void citire_graf(int m, bool o);
void BFS(int start);
void DFSfaraDist(int start, vector<bool>& parcurs);
void DFS(int start, vector<bool>& p, vector<int>& dist, int d);
int Conexe(int n, int s);
void DFSsort(int s, vector<int>& p, stack<int>& st);
void SortTopologica(int n);
void DFSt(int s, vector<int>& p,vector<vector<int> >&s2, int ctc);
void CTC();
pair<int,int> DistMax(vector<int> d);
void diam();
void citire_graf_Floyd();
void Floyd();
void citire_graf2(int m);
void APM();
void unite(int x, int y);
int Find(int x);
void Disjoint(int x, int y, int op);
void unite_disjoint(int n1, int n2);
void initializare_vectori(int m);
void citire_Bellman(int m);
void Dijkstra();
void Bellman_Ford();
};
Graf :: Graf ()
{
orientat = 1;
vector < vector<int> > aux;
noduri = 0;
lista_ad = aux;
}
Graf :: Graf (int n, bool orr)
{ orientat = orr;
noduri = n;
lista_ad.resize(noduri + 1);
}
void Graf :: citire_graf (int muchii, bool orientat)
{
int x,y;
for ( int i = 1; i <= muchii; i++ )
{
fin >> x >> y;
lista_ad[x].push_back(y);
if (orientat == 0)
lista_ad[y].push_back(x);
}
}
void Graf :: BFS(int start)
{
vector <int> dist(noduri+1, -1);
vector <bool> parcurs(noduri+1, 0);
queue <int> q;
dist[start] = 0;
q.push(start);
parcurs[start] = 1;
while (!q.empty())
{
for (int j = 0; j < lista_ad[q.front()].size();j++)
{
int vecin = lista_ad[q.front()][j];
if (parcurs[vecin] == 0)
{
q.push(vecin);
parcurs [vecin] = 1;
dist[vecin] = dist [q.front()] + 1;
}
}
q.pop();}
for (int i = 1; i <= dist.size()-1;i++)
{
gout<< dist[i]<<' ';
}
}
void Graf :: DFSfaraDist(int start, vector<bool>& parcurs)
{
parcurs [start] = 1;
for (int i = 0; i < lista_ad[start].size(); i++)
{
if (parcurs[lista_ad[start][i]] == 0 )
{
DFSfaraDist(lista_ad[start][i],parcurs);
}
}
}
void Graf :: DFS(int start, vector<bool>& parcurs, vector<int>& dist, int d)
{
dist[start] = d;
parcurs [start] = 1;
for (int i = 0; i < lista_ad[start].size(); i++)
{
if (parcurs[lista_ad[start][i]] == 0 )
{
DFS(lista_ad[start][i],parcurs,dist, d+ 1);
}
}
}
void Graf ::DFSsort(int start, vector<int>& parcurs, stack<int>& s)
{
parcurs [start] = 1;
for (int i = 0; i < lista_ad[start].size(); i++)
{
if (parcurs[lista_ad[start][i]] == 0 )
Graf::DFSsort(lista_ad[start][i],parcurs,s);
}
s.push(start);
}
int Graf:: Conexe(int noduri, int start)
{
vector <bool> parcurs1(noduri+1,0);
int CompConexe = 0;
for(int i = 1; i<=noduri; i++)
{
if(parcurs1[i] == 0)
{ CompConexe++;
Graf::DFSfaraDist(i, parcurs1);
}}
return CompConexe;
}
void Graf:: SortTopologica(int noduri)
{
stack <int> s;
vector<int> parcurs(noduri+1, 0);
for(int i = 1; i<=noduri; i++)
{
if(parcurs[i] == 0)
Graf::DFSsort(i, parcurs, s);
}
while(s.empty()==0)
{
gout<<s.top()<<' ';
s.pop();
}
}
void Graf :: DFSt(int start, vector<int>& parcurs,vector<vector<int> >& s2, int ctc)
{
parcurs[start] = 2;
s2[ctc].push_back(start);
for(int i = 0; i < lista_ad_2[start].size(); i++){
if(parcurs[lista_ad_2[start][i]] == 1)
Graf::DFSt(lista_ad_2[start][i], parcurs,s2, ctc);
}
}
void Graf::CTC()
{ int ctc = 0;
stack <int> s;
vector<int> parcurs(noduri+1, 0);
vector<vector<int> > s2;
s2.resize(noduri+1);
for(int i = 1; i<= noduri; i++)
if(parcurs[i] == 0)
Graf::DFSsort(i, parcurs, s);
while (s.empty() == 0)
{
int x = s.top();
if(parcurs[x] == 1)
{
ctc++;
Graf::DFSt(x,parcurs,s2,ctc);
}
s.pop();
}
gout<<ctc;
for (int i = 0; i < s2.size(); i++)
{gout<<'\n';
if (s2[i].size() != 0)
{
for (int j = 0; j < s2[i].size(); j++)
gout << s2[i][j] << ' ';
}
}
}
void SortareDescrescator(vector <int>& a)
{
sort(a.begin(), a.end(), greater<int>());
}
int HavelRez(vector<int> sir_grade)
{
while(sir_grade[0] != 0 )
{
int fst = sir_grade[0];
sir_grade.erase(sir_grade.begin());
if (fst > sir_grade.size())
return 0;
for(int i = 0; i < fst; i++)
{sir_grade[i]--;
if(sir_grade[i] == -1)
return 0;
}
SortareDescrescator(sir_grade);
}
return 1;
}
void Havel()
{int n,x;
cin>>n;
vector <int> sir_grade;
for(int i = 0; i < n; i++)
{
cin>>x;
sir_grade.push_back(x);
}
SortareDescrescator(sir_grade);
if (HavelRez(sir_grade) == 1)
cout<<"Da, se poate forma un graf";
else cout<<"Nu se poate forma un graf";
}
void Graf :: citire_graf2 (int muchii)
{
int x,y,c;
for ( int i = 1; i <= muchii; i++ )
{
cin >> x >> y >>c;
lista_muchii.push_back(make_pair(make_pair(x,y),c));
}
}
int Graf :: Find(int x) {
if(x == reprez[x])
return x;
return Find(reprez[x]);
}
bool SorteazaDupaCost(const pair< pair<int,int>, int> &a,
const pair< pair<int,int>, int> &b)
{
return (a.second < b.second);
}
void Graf:: unite(int nod1,int nod2)
{
int x = Graf::Find(nod1);
int y = Graf::Find(nod2);
if (dim[x] >= dim[y])
{
reprez[y] = x;
dim[x] += dim[y];
muchii++;
}
else
{
reprez[x] = y;
dim[y] += dim[x];
muchii++;
}
}
void Graf:: unite_disjoint(int nod1,int nod2)
{
int x = Graf::Find(nod1);
int y = Graf::Find(nod2);
if (dim[x] >= dim[y])
{
reprez[y] = x;
dim[x] += dim[y];
muchii++;
}
else
{
reprez[x] = y;
dim[y] += dim[x];
muchii++;
}
}
void Graf :: APM()
{ int suma_cost = 0;
muchii = 0;
reprez.resize(noduri+1);
dim.resize(noduri+1);
for(int i = 1; i <= noduri; i++)
{reprez[i] = i;
dim[i] = 1;
}
sort(lista_muchii.begin(), lista_muchii.end(),SorteazaDupaCost);
for (int i = 0; i < lista_muchii.size(); i++)
{ int x = lista_muchii[i].first.first;
int y = lista_muchii[i].first.second;
if(Find(x) != Find(y))
{
rez.push_back(make_pair(y, x));
unite(y,x);
suma_cost+= lista_muchii[i].second;
}}
gout<<suma_cost<<'\n';
gout<<muchii<<'\n';
for(int i = 0; i< muchii; i++)
gout<<rez[i].first << ' ' << rez[i].second<<'\n';
}
void Graf::initializare_vectori(int n)
{
reprez.resize(noduri+1);
dim.resize(noduri+1);
for(int i = 1; i <= n; i++)
{reprez[i] = i;
dim[i] = 1;
}
}
void Graf:: Disjoint(int x, int y, int op)
{
if(op == 1)
unite(x,y);
else
{if(Find(x) == Find(y))
gout<<"DA"<<'\n';
else gout<<"NU"<<'\n';
}
}
void Graf::citire_Bellman(int muchii)
{
int x,y,c;
for ( int i = 1; i <= muchii; i++ )
{
fin >> x >> y >>c;
lista_adiac[x].push_back(make_pair(y,c));
}
}
void Graf::Dijkstra()
{
vector<bool> parcurs;
parcurs.resize(noduri+1);
coada.push(make_pair(0,1));
Dist.resize(noduri+1);
for(int i = 1; i<= noduri;i++)
{
Dist[i] = 10000000;
parcurs[i] = 0;
}
Dist[1] = 0;
while (!coada.empty())
{
int curr = coada.top().second;
if(parcurs[curr] == 1)
continue;
parcurs[curr] = 1;
coada.pop();
for(int i = 0; i < lista_adiac[curr].size();i++)
{
if(Dist[curr] + lista_adiac[curr][i].second < Dist[lista_adiac[curr][i].first])
{
Dist[lista_adiac[curr][i].first]=Dist[curr]+lista_adiac[curr][i].second;
coada.push(make_pair(Dist[lista_adiac[curr][i].first], lista_adiac[curr][i].first));
}
}
}
for(int i = 2; i <= noduri; i++)
if (Dist[i] == 10000000)
gout<<0<<' ';
else
gout<<Dist[i]<<' ';
}
void Graf::Bellman_Ford()
{
bool ok = 1;
vector<bool> in_coada;
vector<int> dist;
vector<int> iteratii;
queue<int> coada;
iteratii.resize(noduri+1);
dist.resize(noduri+1);
in_coada.resize(noduri+1);
for(int i = 1; i<= noduri;i++)
{
dist[i] = 1000000;
iteratii[i] = 0;
}
in_coada[1] = 1;
dist[1] = 0;
coada.push(1);
while (!coada.empty())
{
int curr = coada.front();
in_coada[curr]=0;
iteratii[curr]++;
coada.pop();
if(iteratii[curr] > noduri)
{
gout<<"Ciclu negativ!";
ok = 0;
break;
}
for(int i = 0; i < lista_adiac[curr].size();i++)
{
if(dist[curr] + lista_adiac[curr][i].second < dist[lista_adiac[curr][i].first])
{
dist[lista_adiac[curr][i].first]=dist[curr]+lista_adiac[curr][i].second;
if(!in_coada[curr])
{
coada.push(lista_adiac[curr][i].first);
in_coada[lista_adiac[curr][i].first] = 1;
}
}
}
}
if (ok == 1)
for(int i = 2; i <= noduri; i++)
gout<<dist[i]<<' ';
}
pair<int,int> Graf::DistMax(vector<int> dist) {
int maxim = 0, nod = 0;
for(int i=1;i<=noduri;++i) {
if (dist[i] > maxim) {
maxim = dist[i];
nod = i;
}
}
}
void Graf:: diam()
{
int x;
vector <bool> parcurs(noduri+1,0);
vector <int> dist(noduri+1, 0);
Graf::DFS(1, parcurs, dist, 0);
pair<int,int> nod1 = DistMax(dist);
for(int i=1; i<=noduri; i++)
{
parcurs[i] = 0;
dist[i] = 0;
}
Graf::DFS(nod1.second, parcurs, dist, x);
pair<int,int> nod2 = DistMax(dist);
gout << nod2.first + 1 << '\n';
}
void Graf :: citire_graf_Floyd()
{
int x;
matrice.resize(noduri+1);
for ( int i = 0; i < noduri; i++ )
{
matrice[i].resize(noduri+1);
for (int j = 0; j< noduri; j++)
{
fin>>x;
matrice[i][j] = x;
}
}
}
void Graf::Floyd()
{
vector< vector<int> > dist = matrice;
for (int i = 0; i < noduri; i++)
for (int j = 0; j < noduri; j++)
if(matrice[i][j]==0 && i != j)
dist[i][j] = 100000;
for (int k = 0; k < noduri; k++)
for (int i = 0; i < noduri; i++)
for (int j = 0; j < noduri; j++)
if (dist[i][j] > dist[k][j] + dist[i][k] && i!=j)
dist[i][j] = dist[k][j] + dist[i][k];
for(int i = 0; i < noduri; i++)
{
for (int j = 0; j < noduri; j++)
gout << dist[i][j] << " ";
gout << '\n';
}
}
int main()
{
int n,m;
fin>>n>>m;
Graf g(n,0);
g.citire_graf(m,0);
gout<<g.Conexe(n,1);
return 0;
}