#include <iostream>
#include <vector>
#include <queue>
#include <fstream>
#include <stack>
#include <algorithm>
using namespace std;
#define Nmax 100007
#define Rezolvare 3
const char iname[] = "ctc.in";
const char oname[] = "ctc.out";
vector<int> rev[Nmax];
vector<int> aux;
vector <int> deg;
queue <int> coada;
vector<int> visited;
vector<int> niv_min;
vector<int> nivel,parent;
stack<int> st;
vector<vector<int> > output;
ifstream f(iname);
ofstream g(oname);
class Graph{
public:
Graph(int n, int m);
~Graph();
virtual void add_muchie(int x, int y){}
bool is_correct_graph(vector<int> grade);
private:
protected:
vector<int> la[Nmax]; //lista de adiacenta;
int n,m; //numarul de noduri si numarul de muchii
};
bool Graph::is_correct_graph(vector<int> grade)
{
sort(grade.begin(),grade.end(),greater <int>());
while(grade[0]!=0)
{
int v=grade[0];
grade.erase(grade.begin()+0);
if(v>grade.size())
return false;
for(int i=0;i<v;i++)
{
grade[i]--;
if(grade[i]<0)
return false;
}
sort(grade.begin(),grade.end(),greater <int>());
}
return true;
}
class Undirected: public Graph{
public:
Undirected(int n, int m=0);
~Undirected();
void add_muchie(int x,int y)
{
la[x].push_back(y);
la[y].push_back(x);
}
void dfs(int start,int visited[]);
void criticalConnections(vector<vector<int>>& connections);
void biconex();
private:
void dfs_critical(const int cur);
void util(const int cur,const int parent);
};
int indx=0;
vector <int> out[Nmax];
void Undirected::util(const int cur,const int parent)
{
static int time = 0;
niv_min[cur] = nivel[cur] = ++time;
st.push(cur);
for(int j:la[cur])
{
if(!niv_min[j])
{
util(j,cur);
niv_min[cur] = min(niv_min[cur],niv_min[j]);
if(niv_min[j] >= nivel[cur])
{
indx++;
while(st.top()!=j){
out[indx].push_back(st.top());
st.pop();
}
out[indx].push_back(st.top());
st.pop();
out[indx].push_back(cur);
}
}
else
if(j != parent)
{
niv_min[cur]=min(niv_min[cur],nivel[j]);
}
}
}
void Undirected::biconex()
{
nivel.assign(n+1,-1);
niv_min.resize(n+1);
for(int i=0;i<n;i++)
{
if(!niv_min[i]){
util(i,0);
}
}
g<<indx<<endl;
for(int i=1;i<=indx;i++)
{
for(auto j:out[i])
g<<j<<" ";
g<<endl;
}
}
void Undirected::dfs_critical(int cur)
{
static int time=0;
visited[cur] = 1;
niv_min[cur] = nivel[cur] = ++time;
for(int j:la[cur])
{
if(!visited[j])
{
parent[j] = cur;
dfs_critical(j);
niv_min[cur] = min(niv_min[cur],niv_min[j]);
if(niv_min[j]>nivel[cur])
{
output.push_back({cur,j});
}
}
else
if(j!=parent[cur])
{
niv_min[cur]=min(niv_min[cur],nivel[j]);
}
}
}
void Undirected::criticalConnections(vector<vector<int>>& connections) {
n=this->n;
parent.assign(n+1,-1);
visited.assign(n+1,0);
niv_min.resize(n+1);
nivel.resize(n+1);
for(int i = 0; i < connections.size(); i++)
{
la[connections[i][0]].push_back(connections[i][1]);
la[connections[i][1]].push_back(connections[i][0]);
}
for(int i=0;i<n;i++)
{
if(visited[i]==0){
dfs_critical(i);
}
}
for(int i=0;i<output.size();i++)
cout<<output[i][0]<<" "<<output[i][1]<<endl;
}
int nr_conex=0;
void Undirected::dfs(int start,int visited[])
{
visited[start] = nr_conex;
for(auto i:la[start])
{
if(!visited[i])
dfs(i,visited);
}
}
Undirected::Undirected(int n, int m): Graph(n,m)
{
}
Undirected::~Undirected()
{
}
class Directed: public Graph{
public:
Directed(int n,int m);
~Directed();
void add_muchie(int x,int y);
void bfs(int start, int visited[],int dist[]);
void findCTC();
void reverse();
void topologic(vector <int>& deg);
private:
void dfs_plus(int i,stack<int> &my_stack,int visited[]);
void dfs_reverse(int i,vector <int>& aux,int visited[]);
};
void Directed::topologic(vector <int>& deg)
{
for(int i=1;i<=n;i++)
if(!deg[i]) coada.push(i);
while(!coada.empty())
{
for(auto j:la[coada.front()])
{
deg[j]--;
if(!deg[j]) coada.push(j);
}
g<<coada.front()<<" ";
coada.pop();
}
}
void Directed::dfs_reverse(int i,vector <int>& aux,int visited[])
{
visited[i]=1;
for(auto j:rev[i])
{
if(!visited[j])
dfs_reverse(j,aux,visited);
}
aux.push_back(i);
}
void Directed::findCTC()
{
int visited[n];
vector< vector<int> > sol;
for(int i=1;i<=n;i++)
visited[i]=0;
stack<int> my_stack;
for(int i=1;i<=n;i++)
if(!visited[i])
dfs_plus(i,my_stack,visited);
for(int i=1;i<=n;i++)
visited[i]=0;
int scc = 0;
while(!my_stack.empty())
{
int cur = my_stack.top();
my_stack.pop();
if(!visited[cur])
{
aux = vector<int>();
dfs_reverse(cur,aux,visited);
sol.push_back(aux);
scc++;
}
}
g<<scc<<"\n";
for(int i=0;i<sol.size();i++)
{
for(int j=0;j<sol[i].size();j++)
g<<sol[i][j]<<" ";
g<<"\n";
}
}
void Directed::reverse()
{
for(int i=1;i<=n;i++)
{
for(int j:la[i])
rev[j].push_back(i);
}
}
void Directed::dfs_plus(int i,stack<int> &my_stack,int visited[])
{
visited[i]=1;
for(int j:la[i])
{
if(!visited[j])
dfs_plus(j,my_stack,visited);
}
my_stack.push(i);
}
Directed::Directed(int n, int m): Graph(n,m)
{
}
Directed::~Directed()
{
}
void Directed::add_muchie(int x,int y)
{
la[x].push_back(y);
}
void Directed::bfs(int start, int visited[],int dist[]){
queue <int> coada;
visited[start]=true;
coada.push(start);
dist[start] = 0;
while(!coada.empty())
{ start = coada.front();
coada.pop();
for(auto i:la[start])
{
if(!visited[i])
{
visited[i] = true;
coada.push(i);
dist[i]=dist[start]+1;
}
}
}
}
Graph::Graph(int n=0, int m=0):n(n),m(m)
{
}
Graph::~Graph()
{
}
int main()
{
int n,m,s;
int x,y;
switch(Rezolvare)
{
case 1:
{
f>>n>>m>>s;
Directed grf(n,m);
for(int i=0;i<m;i++)
{
f>>x>>y;
grf.add_muchie(x,y);
}
f.close();
int visited[n],dist[n];
for(int i=0;i<=n;i++)
visited[i]=dist[i]=0;
grf.bfs(s,visited,dist);
for(int i=1;i<=n;i++)
{
if(visited[i])
g<<dist[i]<<" ";
else g<<-1<<" ";
}
break;
}
case 2:
{
f>>n>>m;
Undirected grf(n,m);
int visited[n];
for(int i=0;i<m;i++)
{
f>>x>>y;
grf.add_muchie(x,y);
}
for(int i=0;i<=n;i++)
visited[i]=0;
for(int i=1;i<=n;i++)
if(!visited[i])
{
nr_conex++;
grf.dfs(i,visited);
}
g<<nr_conex;
break;
}
case 3:
{
f>>n>>m;
Directed grf(n,m);
for(int i=0;i<m;i++)
{
f>>x>>y;
grf.add_muchie(x,y);
}
grf.reverse();
grf.findCTC();
break;
}
case 4:
{
vector<int> check;
int number;
cin>>number;
for(int i=0;i<number;i++)
{
int c;
cin>>c;
check.push_back(c);
}
Graph grf(n);
if(grf.is_correct_graph(check))
cout<<"DA";
else cout<<"NU";
break;
}
case 5:
{
f>>n>>m;
Directed grf(n,m);
deg = vector<int>(n+1,0);
for(int i=0;i<m;i++)
{
f>>x>>y;
grf.add_muchie(x,y);
deg[y]++;
}
f.close();
grf.topologic(deg);
break;
}
case 6:
{
Undirected grf(4,0);
vector<vector<int> > connections;
connections.push_back({0,1});
connections.push_back({1,2});
connections.push_back({2,0});
connections.push_back({1,3});
grf.criticalConnections(connections);
break;
}
case 7:
{
f>>n>>m;
Undirected grf(n,m);
for(int i=0;i<m;i++)
{
f>>x>>y;
grf.add_muchie(x,y);
}
grf.biconex();
break;
}
}
g.close();
return 0;
}