#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <algorithm>
#include <unordered_map>
#include <set>
#include <deque>
#include <queue>
#include <climits>
#define PROBLEMA 13
#define inf INT_MAX-1000000
using namespace std;
ifstream f;
ofstream g;
class graf
{
unsigned int n,m;
vector< vector<pair<int,int> > > lista_vecini;
void BFS(unsigned int,int*);
void DFS(unsigned int, bool*,unsigned int&);
void biconex(unsigned int, int*, int*, unsigned int&, stack<pair<unsigned int, unsigned int>>&, vector<unsigned int>&);
void ctc(unsigned int, int*, int*, bool*, unsigned int&, unsigned int&, stack<unsigned int>&, vector <unsigned int>&);
void sortaret(unsigned int, bool*, stack<unsigned int>&);
vector<vector<int>> criticalConnections(int,vector<vector<int>>&);
public:
graf(const unsigned int &);
~graf();
void setn(const unsigned int &);
void setm(const unsigned int &);
int getn();
int getm();
void getvecini();
void sortvecini();
void StartBFS();
void StartDFS();
void Startbiconex();
void Startctc();
void Startsortaret();
void havelhakimi();
void StartcriticalConnections();
void apm();
void disjoint();
void dijkstra();
void Bellman_Ford();
void royfloyd();
void darb();
};
graf::graf(const unsigned int &opt=0)
{
switch (opt)
{
case 1:
case 3:
case 4:
{
unsigned int x,y,cost;
f>>this->n>>this->m;
if (opt==1)
f>>x;
this->lista_vecini.resize(n+1);
for (unsigned int i=0; i<this->m; ++i)
{
f>>x>>y;
if (opt==1 || opt==3)
this->lista_vecini[x].push_back(make_pair(y,0));
else
{
f>>cost;
this->lista_vecini[x].push_back(make_pair(y,cost));
}
}
break;
}
case 2:
case 5:
case 6:
{
unsigned int x,y,cost;
if (opt!=6)
f>>this->n>>this->m;
else
{
f>>this->n;
this->m=this->n-1;
}
this->lista_vecini.resize(n+1);
for (unsigned int i=0; i<this->m; ++i)
{
f>>x>>y;
if (opt!=5)
{
this->lista_vecini[x].push_back(make_pair(y,0));
this->lista_vecini[y].push_back(make_pair(x,0));
}
else
{
f>>cost;
this->lista_vecini[x].push_back(make_pair(y,cost));
this->lista_vecini[y].push_back(make_pair(x,cost));
}
}
break;
}
default:
break;
}
}
graf::~graf()
{
//simbolic
this->n=this->m=0;
for (size_t i=0; i<this->lista_vecini.size(); ++i)
this->lista_vecini[i].clear();
this->lista_vecini.clear();
}
void graf::setn(const unsigned int &n)
{
this->n=n;
}
void graf::setm(const unsigned int &m)
{
this->m=m;
}
int graf::getm()
{
return this->m;
}
int graf::getn()
{
return this->n;
}
void graf::getvecini()
{
for (unsigned int i=1-min(1,int(lista_vecini[0].size())); i<this->lista_vecini.size()-min(1,int(lista_vecini[0].size())); ++i)
{
cout<<i<<": ";
for (unsigned int j=0; j<this->lista_vecini[i].size(); ++j)
cout<<this->lista_vecini[i][j].first<<" ";
cout<<"\n";
}
}
void graf::sortvecini()
{
unsigned int j,k;
unsigned int ap[this->n+1];
for (j=0; j<=this->n; ++j)
ap[j]=0;
for (unsigned int i=1; i<this->lista_vecini.size(); ++i)
{
k=0;
for (j=0; j<this->lista_vecini[i].size(); ++j)
++ap[this->lista_vecini[i][j].first];
for (j=1; j<=this->n; ++j)
{
if (ap[j])
{
this->lista_vecini[i][k++].first=j;
ap[j]=0;
}
}
}
}
void graf::StartBFS()
{
ifstream h;
unsigned int start;
h.open("bfs.in",std::ifstream::in);
h>>start>>start>>start;
h.close();
int d[this->n+1];
for (unsigned int i=1; i<=this->n; ++i)
d[i]=-1;
BFS(start,d);
for (unsigned int i=1; i<=this->n; ++i)
{
g<<d[i]<<" ";
}
}
void graf::BFS(unsigned int nod_start,int d[])
{
unsigned int index=0;
vector <int> coada;
coada.push_back(nod_start);
d[nod_start]=0;
while (index<coada.size())
{
int nod_curent=coada[index++];
for (unsigned int i=0; i<this->lista_vecini[nod_curent].size(); ++i)
if (d[this->lista_vecini[nod_curent][i].first]==-1)
{
coada.push_back(this->lista_vecini[nod_curent][i].first);
d[this->lista_vecini[nod_curent][i].first]=d[nod_curent]+1;
}
}
}
void graf::StartDFS()
{
bool viz[this->n+1];
unsigned int nrconex;
for (unsigned int i=1; i<=this->n; ++i)
viz[i]=false;
nrconex=0;
for (unsigned int i=1; i<=this->n; ++i)
if (!viz[i])
{
nrconex++;
DFS(i,viz,nrconex);
}
g<<nrconex;
}
void graf::DFS(unsigned int nod_curent,bool viz[],unsigned int &nrconex)
{
viz[nod_curent]=true;
for (unsigned int i=0; i<this->lista_vecini[nod_curent].size(); ++i)
if (!viz[this->lista_vecini[nod_curent][i].first])
DFS(this->lista_vecini[nod_curent][i].first,viz,nrconex);
}
void graf::Startbiconex()
{
int niv[this->n+1];
int niv_int[this->n+1];
unsigned int nrbiconex=0;
stack <pair<unsigned int,unsigned int>> stiva;
vector <unsigned int> sol;
for (unsigned int i=1; i<=this->n; ++i)
{
niv[i]=-1;
niv_int[i]=0;
}
niv[1]=0;
biconex(1,niv,niv_int,nrbiconex,stiva,sol);
g<<nrbiconex<<"\n";
for (auto i = sol.begin(); i != sol.end(); ++ i)
if (*i!=0)
g<<*i<<" ";
else
g<<"\n";
}
void graf::biconex(unsigned int nod_curent,int niv[],int niv_int[],unsigned int &nrbiconex,stack <pair<unsigned int,unsigned int>> &stiva,vector <unsigned int> &sol)
{
for (unsigned int i=0; i<this->lista_vecini[nod_curent].size(); ++i)
if (niv[this->lista_vecini[nod_curent][i].first]==-1)
{
niv[this->lista_vecini[nod_curent][i].first]=niv[nod_curent]+1;
niv_int[this->lista_vecini[nod_curent][i].first]=niv[nod_curent]+1;
stiva.push(make_pair(nod_curent,this->lista_vecini[nod_curent][i].first));
biconex(this->lista_vecini[nod_curent][i].first,niv,niv_int,nrbiconex,stiva,sol);
niv_int[nod_curent]=min(niv_int[nod_curent],niv_int[this->lista_vecini[nod_curent][i].first]);
if (niv_int[this->lista_vecini[nod_curent][i].first]>=niv[nod_curent])
{
nrbiconex++;
unordered_map<unsigned int,bool> ap;
unsigned int aux1;
unsigned int aux2;
do
{
aux1=stiva.top().first;
aux2=stiva.top().second;
if (!ap[aux1])
{
sol.push_back(aux1);
ap[aux1]=1;
}
if (!ap[aux2])
{
sol.push_back(aux2);
ap[aux2]=1;
}
stiva.pop();
}
while(aux1!=nod_curent || aux2!=this->lista_vecini[nod_curent][i].first);
sol.push_back(0);
}
}
else if (niv[nod_curent]-1!=niv[this->lista_vecini[nod_curent][i].first])
niv_int[nod_curent]=min(niv_int[nod_curent],niv[this->lista_vecini[nod_curent][i].first]);
//scadem 1 ca sa nu luam in considerare si tatal nodului
}
void graf::Startctc()
{
int indx[this->n+1];
int indx_min[this->n+1];
bool peStiva[this->n+1];
unsigned int nrctc=0;
unsigned int it=1;
unsigned int i;
stack <unsigned int> stiva;
vector <unsigned int> sol;
for (i=1; i<=this->n; ++i)
{
indx[i]=-1;
indx_min[i]=0;
peStiva[i]=false;
}
for(i=1; i<=this->n; ++i)
if (indx[i]==-1)
ctc(i,indx,indx_min,peStiva,nrctc,it,stiva,sol);
g<<nrctc<<"\n";
for (auto i = sol.begin(); i != sol.end(); ++ i)
if (*i!=0)
g<<*i<<" ";
else
g<<"\n";
}
void graf::ctc(unsigned int nod_curent,int indx[], int indx_min[], bool peStiva[], unsigned int &nrctc, unsigned int &it, stack<unsigned int> &stiva, vector<unsigned int> &sol)
{
indx[nod_curent]=it;
indx_min[nod_curent]=it++;
stiva.push(nod_curent);
peStiva[nod_curent]=true;
for (unsigned int i=0; i<this->lista_vecini[nod_curent].size(); ++i)
if (indx[this->lista_vecini[nod_curent][i].first]==-1)
{
ctc(this->lista_vecini[nod_curent][i].first,indx,indx_min,peStiva,nrctc,it,stiva,sol);
indx_min[nod_curent]=min(indx_min[nod_curent],indx_min[this->lista_vecini[nod_curent][i].first]);
}
else if (peStiva[this->lista_vecini[nod_curent][i].first])
indx_min[nod_curent]=min(indx_min[nod_curent],indx[this->lista_vecini[nod_curent][i].first]);
if (indx_min[nod_curent]==indx[nod_curent])
{
++nrctc;
unsigned int nod_aux;
do
{
nod_aux=stiva.top();
peStiva[nod_aux]=false;
sol.push_back(nod_aux);
stiva.pop();
}
while (nod_aux!=nod_curent);
sol.push_back(0);
}
}
void graf::Startsortaret()
{
bool viz[this->n+1];
stack <unsigned int> sol;
unsigned int i;
for (i=1; i<=this->n; ++i)
viz[i]=false;
for (i=1; i<=this->n; ++i)
if (!viz[i])
sortaret(i, viz, sol);
while (!sol.empty())
{
//afisam in postordine invers
g<<sol.top()<<" ";
sol.pop();
}
}
void graf::sortaret(unsigned int nod_curent, bool viz[], stack<unsigned int> &sol)
{
viz[nod_curent]=true;
for (unsigned int i=0; i<this->lista_vecini[nod_curent].size(); ++i)
if (!viz[lista_vecini[nod_curent][i].first])
{
sortaret(lista_vecini[nod_curent][i].first, viz, sol);
}
//introducem nodurile in postordine (dupa ce ies din stiva) in stiva solutie
sol.push(nod_curent);
}
void graf::havelhakimi()
{
bool zero=false;
int vmax=0;
vector <int> grad;
unsigned int x;
while (f>>x)
grad.push_back(x);
while (!zero)
{
zero=true;
int ap[grad.size()+1];
int k=0;
for (unsigned int i=0; i<=grad.size(); ++i)
ap[i]=0;
for (unsigned int i=0; i<grad.size(); ++i)
{
++ap[grad[i]];
vmax=max(vmax,grad[i]);
}
for (unsigned int i=0; i<=vmax; ++i)
for (unsigned int j=0; j<ap[i]; ++j)
grad[k++]=i;
unsigned int nrs=grad[grad.size()-1];
grad.pop_back();
if (nrs>grad.size())
{
cout<<"Nu";
g<<"Nu";
return;
}
for (unsigned int i=grad.size()-1; (int)(i)>(int)(grad.size()-nrs-1); --i)
{
--grad[i];
if (grad[i]<0)
{
cout<<"Nu";
g<<"Nu";
return;
}
if (grad[i]!=0)
zero=false;
}
}
cout<<"Da";
g<<"Da";
}
void graf::StartcriticalConnections()
{
vector<vector<int>> muchii;
int n,x,y,m;
unsigned int nrt;
f>>nrt;
for (unsigned int t=0; t<nrt; ++t)
{
muchii.resize(0);
f>>n>>m;
for (int i=0; i<m; ++i)
{
f>>x>>y;
muchii.push_back(vector<int> {x,y});
}
vector<vector<int>> sol(this->criticalConnections(n,muchii));
for (size_t i=0; i<sol.size(); ++i)
{
cout<<"("<<sol[i][0]<<","<<sol[i][1]<<") ";
g<<"("<<sol[i][0]<<","<<sol[i][1]<<") ";
}
cout<<"\n\n";
g<<"\n\n";
}
}
vector<vector<int>> graf::criticalConnections(int n, vector<vector<int>>& connections)
{
unsigned int i;
this->setn(n);
this->setm(connections.size());
stack <unsigned int> stiva;
vector<vector<int>> sol;
unsigned int icopil[n];
this->lista_vecini.clear();
this->lista_vecini.resize(n);
int niv[n];
int niv_int[n];
for (int i=0; i<n; ++i)
{
niv[i]=-1;
niv_int[i]=0;
icopil[i]=0;
}
for (i=0; i<connections.size(); ++i)
{
this->lista_vecini[connections[i][0]].push_back(make_pair(connections[i][1],0));
this->lista_vecini[connections[i][1]].push_back(make_pair(connections[i][0],0));
}
niv[0]=1;
stiva.push(0);
while (!stiva.empty())
{
unsigned int nod_curent=stiva.top();
for (i=icopil[nod_curent]; i<this->lista_vecini[nod_curent].size(); ++i)
{
++icopil[nod_curent];
if (niv[this->lista_vecini[nod_curent][i].first]==-1)
{
niv[this->lista_vecini[nod_curent][i].first]=niv[nod_curent]+1;
niv_int[this->lista_vecini[nod_curent][i].first]=niv[nod_curent]+1;
stiva.push(this->lista_vecini[nod_curent][i].first);
nod_curent=this->lista_vecini[nod_curent][i].first;
break;
}
else if (niv[nod_curent]-1!=niv[this->lista_vecini[nod_curent][i].first])
niv_int[nod_curent]=min(niv_int[nod_curent],niv[this->lista_vecini[nod_curent][i].first]);
}
if (icopil[nod_curent]==this->lista_vecini[nod_curent].size())
{
unsigned int copil=stiva.top();
stiva.pop();
if (!stiva.empty())
{
niv_int[stiva.top()]=min(niv_int[copil],niv_int[stiva.top()]);
if (niv_int[copil]>niv[stiva.top()])
sol.push_back({int(stiva.top()),int(copil)});
}
}
}
return sol;
}
void graf::apm()
{
unsigned int x,y;
int cost_total=0;
f>>this->n>>this->m;
int tata[n+1];
int inaltime[n+1];
vector<pair<int,pair<int,int>>> lista_muchii_greutati;
lista_muchii_greutati.resize(this->n+1);
vector<pair<int,int>> sol;
for (unsigned int i=0; i<this->m; ++i)
{
int cost;
f>>x>>y>>cost;
lista_muchii_greutati.push_back(make_pair(cost,make_pair(x,y)));
}
for (unsigned int i=0; i<=n; ++i)
{
tata[i]=0;
inaltime[i]=1;
}
sort(lista_muchii_greutati.begin(),lista_muchii_greutati.end());
unsigned int nrm=0;
for (unsigned int i=0; i<lista_muchii_greutati.size() && nrm!=this->n-1; ++i)
{
int x=lista_muchii_greutati[i].second.first,y=lista_muchii_greutati[i].second.second;
int cost_muchie=lista_muchii_greutati[i].first;
int rx=x,ry=y,aux;
while (tata[rx]!=0)
rx=tata[rx];
while (tata[ry]!=0)
ry=tata[ry];
if (rx==ry)
{
}
else
{
sol.push_back(make_pair(x,y));
++nrm;
cost_total+=cost_muchie;
int hx=inaltime[rx];
int hy=inaltime[ry];
if (hx<hy)
{
tata[rx]=ry;
inaltime[ry]=max(hy,hx+1);
}
else
{
tata[ry]=rx;
inaltime[rx]=max(hx,hy+1);
}
}
while (x!=rx)
{
aux=tata[x];
tata[x]=rx;
x=aux;
}
while (y!=ry)
{
aux=tata[y];
tata[y]=ry;
y=aux;
}
}
g<<cost_total<<"\n"<<this->n-1<<"\n";
for (unsigned int i=0; i<sol.size(); ++i)
g<<sol[i].first<<" "<<sol[i].second<<"\n";
}
void graf::disjoint()
{
int n,m;
f>>n>>m;
int tata[n+1];
int inaltime[n+1];
for (unsigned int i=0; i<=n; ++i)
{
tata[i]=0;
inaltime[i]=1;
}
int op,x,y;
while (f>>op>>x>>y)
{
if (op==1)
{
while (tata[x]!=0)
x=tata[x];
while (tata[y]!=0)
y=tata[y];
int hx=inaltime[x];
int hy=inaltime[y];
if (hx<hy)
{
tata[x]=y;
inaltime[y]=max(hy,hx+1);
}
else
{
tata[y]=x;
inaltime[x]=max(hx,hy+1);
}
}
else
{
int rx=x,ry=y,aux;
while (tata[rx]!=0)
rx=tata[rx];
while (tata[ry]!=0)
ry=tata[ry];
if (rx==ry)
g<<"DA\n";
else
g<<"NU\n";
while (x!=rx)
{
aux=tata[x];
tata[x]=rx;
x=aux;
}
while (y!=ry)
{
aux=tata[y];
tata[y]=ry;
y=aux;
}
}
}
}
void graf::dijkstra()
{
unsigned int i;
int d[this->n+1];
set<pair<int,int>> set_noduri;
for (i=1; i<=this->n; ++i)
{
d[i]=inf;
}
d[1]=0;
set_noduri.insert(make_pair(0,1));
while (!set_noduri.empty())
{
int nod=(*set_noduri.begin()).second;
set_noduri.erase(set_noduri.begin());
for (int i=0; i<this->lista_vecini[nod].size(); ++i)
{
int nod_dest=this->lista_vecini[nod][i].first;
int cost_dest=this->lista_vecini[nod][i].second;
if (d[nod]+cost_dest<d[nod_dest])
{
if (d[nod_dest]!=inf)
{
set_noduri.erase(set_noduri.find(make_pair(d[nod_dest],nod_dest)));
}
d[nod_dest]=d[nod]+cost_dest;
set_noduri.insert(make_pair(d[nod_dest],nod_dest));
}
}
}
for (unsigned int i=2; i<=this->n; ++i)
if (d[i]!=inf)
g<<d[i]<<" ";
else
g<<0<<" ";
}
void graf::Bellman_Ford()
{
unsigned int i;
f>>this->n>>this->m;
int d[this->n+1];
int nrCoada[this->n+1];
bool inCoada[this->n+1];
bool ciclu_negativ=false;
queue<int> noduri;
for (i=1; i<=this->n; ++i)
{
d[i]=inf;
inCoada[i]=false;
nrCoada[i]=0;
}
d[1]=0;
noduri.push(1);
nrCoada[1]=1;
while (!noduri.empty() && !ciclu_negativ)
{
int nod_curent=noduri.front();
noduri.pop();
inCoada[nod_curent]=false;
for (i=0; i<this->lista_vecini[nod_curent].size(); ++i)
{
int nod_dest=this->lista_vecini[nod_curent][i].first;
int cost_dest=this->lista_vecini[nod_curent][i].second;
if (d[nod_curent]+cost_dest<d[nod_dest])
{
d[nod_dest]=d[nod_curent]+cost_dest;
if (!inCoada[nod_dest])
{
if (nrCoada[nod_dest]>this->n)
{
ciclu_negativ=true;
}
noduri.push(nod_dest);
inCoada[nod_dest]=true;
++nrCoada[nod_dest];
}
}
}
}
if (ciclu_negativ)
g<<"Ciclu negativ!";
else
for (i=2; i<=this->n; ++i)
g<<d[i]<<" ";
}
void graf::royfloyd()
{
int dist[101][101];
unsigned int i,j,k;
f>>this->n;
for (i=1; i<=this->n; ++i)
for (j=1; j<=this->n; ++j)
{
f>>dist[i][j];
if (dist[i][j]==0)
dist[i][j]=inf-10000;
}
for (k=1; k<=this->n; ++k)
for (i=1; i<=this->n; ++i)
for (j=1; j<=this->n; ++j)
if (dist[i][k]+dist[k][j]<dist[i][j])
dist[i][j]=dist[i][k]+dist[k][j];
for (i=1; i<=this->n; ++i)
{
for (j=1; j<=this->n; ++j)
if (dist[i][j]==inf-10000 || i==j)
g<<0<<" ";
else
g<<dist[i][j]<<" ";
g<<"\n";
}
}
void graf::darb()
{
int d[this->n+1];
unsigned int i;
for (i=1; i<=this->n; ++i)
d[i]=-1;
BFS(1,d);
int vmax=0;
int nod_max=0;
for (i=1; i<=this->n; ++i)
{
if (d[i]>vmax)
{
vmax=d[i];
nod_max=i;
}
d[i]=-1;
}
BFS(nod_max,d);
vmax=d[1];
for (i=2; i<=this->n; ++i)
{
if (d[i]>vmax)
vmax=d[i];
}
g<<vmax+1;
}
int main()
{
switch (PROBLEMA)
{
case 1:
{
f.open ("bfs.in", std::ifstream::in);
g.open ("bfs.out", std::ifstream::out);
graf a(1);
a.StartBFS();
break;
}
case 2:
{
f.open ("dfs.in", std::ifstream::in);
g.open ("dfs.out", std::ifstream::out);
graf a(2);
a.StartDFS();
break;
}
case 3:
{
f.open("biconex.in",std::fstream::in);
g.open("biconex.out",std::fstream::out);
graf a(2);
a.Startbiconex();
break;
}
case 4:
{
f.open("ctc.in",std::fstream::in);
g.open("ctc.out",std::fstream::out);
graf a(3);
a.Startctc();
break;
}
case 5:
{
f.open("sortaret.in",std::fstream::in);
g.open("sortaret.out",std::fstream::out);
graf a(3);
a.Startsortaret();
break;
}
case 6:
{
f.open("havelhakimi.in",std::fstream::in);
g.open("havelhakimi.out",std::fstream::out);
graf a;
a.havelhakimi();
break;
}
case 7:
{
f.open("criticalConnections.in",std::fstream::in);
g.open("criticalConnections.out",std::fstream::out);
graf a;
a.StartcriticalConnections();
break;
}
case 8:
{
f.open("apm.in",std::fstream::in);
g.open("apm.out",std::fstream::out);
graf a;
a.apm();
break;
}
case 9:
{
f.open("disjoint.in",std::fstream::in);
g.open("disjoint.out",std::fstream::out);
graf a;
a.disjoint();
break;
}
case 10:
{
f.open("dijkstra.in",std::fstream::in);
g.open("dijkstra.out",std::fstream::out);
graf a(4);
a.dijkstra();
break;
}
case 11:
{
f.open("bellmanford.in",std::fstream::in);
g.open("bellmanford.out",std::fstream::out);
graf a(4);
a.Bellman_Ford();
break;
}
case 13:
{
f.open("royfloyd.in",std::fstream::in);
g.open("royfloyd.out",std::fstream::out);
graf a;
a.royfloyd();
break;
}
case 14:
{
f.open("darb.in",std::fstream::in);
g.open("darb.out",std::fstream::out);
graf a(6);
a.darb();
break;
}
default:
break;
}
f.close();
g.close();
}