#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
#define N 100001
#define NN 101
#define Nb 50001
#define Nd 50001
#define Md 250001
#define inf 0x3f3f3f3f
#define oo 0x3f3f3f3f
using namespace std;
class Graph {
public:
//structuri
struct Muchie{
int x;
int y;
int cost;
};
//vectori
vector <int> adiacenta[N];
vector <int> solution;
vector<Muchie> muchii;
vector<Muchie> rezultat;
//arrays
bool visited[N];
int T[N]; //vectorul de tati
int S[N]; //vector de sizes
int contor[N];
//variabile
int cost_total = 0;
int diametru = 0;
int last;
//functii
void addEdge_neorientat(int h, int t);
void addEdge_orientat(int h, int t);
void DFS(int vf);
void Solve_Conexe_DFS();
void BFS_mininum_distances(int root, int n);
void Solve_Min_Dist_BFS();
void Solve_Sortaret();
void Solve_APM();
static bool compareByCost(Muchie a, Muchie b);
static bool cuplaj(int x, int (&visited)[N], int (&dr)[N], int (&st)[N], vector<int> (&a)[N]);
int find(int x);
void connect(int x, int y);
void kruskal();
void Solve_Disjoint();
void Solve_Diametru();
void bfs(int start, queue<int>& coada);
void Solve_RoyFloyd();
void Solve_Roy();
void Solve_Eulerian();
void Solve_Cuplaj();
void add_bellman(int x, bool (&in_q)[Nb], int (&q)[Nb+2], int cnt_q[Nb], int &dr);
void Solve_Bellmanford();
void Solve_Dijkstra();
};
void Graph::addEdge_neorientat(int h,int t)
{
adiacenta[h].push_back(t);
adiacenta[t].push_back(h);
}
void Graph::addEdge_orientat(int h,int t)
{
adiacenta[h].push_back(t);
}
void Graph::DFS(int vf)
{
visited[vf] = true;
for(int i = 0; i < adiacenta[vf].size(); ++i)
if (!visited[adiacenta[vf][i]])
DFS(adiacenta[vf][i]);
solution.push_back(vf);
}
void Graph::Solve_Conexe_DFS()
{
ifstream fin("dfs.in");
ofstream fout("dfs.out");
int n, m, n1, n2, conexe = 0;
fin>>n>>m;
for (int i = 1; i <= m; i++)
{
fin >> n1 >> n2;
addEdge_neorientat(n1,n2);
}
for(int i = 1; i <= n; i++){
if (!visited[i])
{
conexe += 1;
DFS(i);
}
}
fout << conexe;
fin.close();
}
void Graph::BFS_mininum_distances(int root, int n)
{
ofstream fout("bfs.out");
vector<int> d(n + 1, -1);
queue<int> q;
d[root] = 0;
q.push(root);
while (!q.empty()) {
int current = q.front();
q.pop();
for (auto &index : adiacenta[current]) {
if (d[index] == -1)
{
d[index] = d[current] + 1;
q.push(index);
}
}
}
for (int i = 1; i <= n; ++i) {
fout << d[i] << ' ';
}
}
void Graph::Solve_Min_Dist_BFS()
{
ifstream fin("bfs.in");
int n, m, n1, n2, s;
fin>>n>>m>>s;
for (int i = 1; i <= m; i++)
{
fin >> n1 >> n2;
addEdge_orientat(n1,n2);
}
BFS_mininum_distances(s, n);
fin.close();
}
void Graph::Solve_Sortaret()
{
ifstream fin("sortaret.in");
ofstream fout("sortaret.out");
int n, m, n1, n2;
fin>>n>>m;
for (int i = 1; i <= m; i++)
{
fin >> n1 >> n2;
addEdge_orientat(n1,n2);
}
for (int i = 1; i <= n; ++i)
{
if (!visited[i])
DFS(i);
}
int upper_limit = solution.size() - 1;
for (int i = upper_limit; i > -1; i--)
fout << solution[i] << ' ';
fin.close();
}
bool Graph::compareByCost(Muchie a, Muchie b)
{
return a.cost < b.cost;
}
int Graph::find(int x){
while (x != T[x]) {
x = T[x];
find(x);
}
return x;
}
void Graph::connect(int x, int y){
int T_X = find(x), T_Y = find(y);
if (S[T_X] >= S[T_Y]) {
T[T_Y] = T_X;
S[T_X] += S[T_Y];
}
else
{
S[T_Y] += S[T_X];
T[T_X] = T_Y;
}
}
void Graph::kruskal()
{
for (auto muchie : muchii){
if (find(muchie.x) != find(muchie.y)) {
connect(muchie.x,muchie.y);
cost_total += muchie.cost;
rezultat.push_back({muchie.x,muchie.y,0});
}
}
}
void Graph::Solve_APM()
{
ifstream fin("apm.in");
ofstream fout("apm.out");
int n, M, n1, n2;
fin>>n>>M;
Muchie m;
for (int i = 0; i < M; i++)
{
fin>>m.x>>m.y>>m.cost;
muchii.push_back(m);
}
sort(muchii.begin(), muchii.end(), compareByCost);
for (int i=0; i<=n; i++) {
T[i] = i;
S[i] = 1;
}
kruskal();
fout << cost_total << "\n" << rezultat.size() << "\n";
for (int i = 0; i < rezultat.size(); i++)
{
fout<<rezultat[i].x<<' '<<rezultat[i].y<<endl;
}
fin.close();
}
void Graph::Solve_Disjoint()
{
ifstream fin("disjoint.in");
ofstream fout("disjoint.out");
int n, m, cod, x, y;
fin>>n>>m;
for (int i=0; i<=n; i++) {
T[i] = i;
S[i] = 1;
}
for(int i = 0; i < m; ++i)
{
fin>>cod>>x>>y;
if(cod == 1)
{
connect(x, y);
}
if(cod == 2)
{
if(find(x) == find(y))
{
fout<<"DA";
}
else
{
fout<<"NU";
}
fout<<endl;
}
}
fin.close();
}
void Graph::bfs(int start, queue<int>& coada)
{
coada.push(start);
contor[start]=1;
visited[start] = true;
while(!coada.empty()){
int el=coada.front();
for(int i=0;i<adiacenta[el].size();i++){
if(visited[adiacenta[el][i]]== false){
coada.push(adiacenta[el][i]);
contor[adiacenta[el][i]]=contor[el]+1;
visited[adiacenta[el][i]] = true ;
diametru=contor[adiacenta[el][i]];
last=adiacenta[el][i];
}
}
coada.pop();
}
}
void Graph::Solve_Diametru()
{
ifstream fin("darb.in");
ofstream fout("darb.out");
queue<int> q;
int n, m, n1, n2;
fin>>n;
m = n - 1; //nr de muchii
for(int i = 1; i <= m; ++i)
{
fin>>n1>>n2;
addEdge_neorientat(n1,n2);
}
bfs(1,q);
//implementez solutia de 100 de puncte: 2 parcurgeri cu DFS
//prima dintr-un nod oarecare: la mine va fi 1
//a doua din nodul in care am ajuns
for(int i = 1; i <= n; i++)
visited[i] = false;
bfs(last, q);
fout<<diametru;
}
void Graph::Solve_Roy()
{
ifstream in("royfloyd.in");
ofstream out("royfloyd.out");
int n;
in>>n;
int m[101][101];
// practic, k = 0 case
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
in>>m[i][j];
if (i != j && !m[i][j])
m[i][j] = oo;
}
}
for(int k = 0; k < n; ++k)
{
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(m[i][k] + m[k][j] < m[i][j]) //vad care e drumul mai scurt dintre i->k->j , respectiv cel de pana acum
{
m[i][j] = m[i][k] + m[k][j];
}
}
}
}
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if (m[i][j] != oo)
out<<m[i][j]<<' ';
else out << 0;
}
out<<endl;
}
}
void Graph::Solve_Eulerian() {
ifstream in("ciclueuler.in");
ofstream out("ciclueuler.out");
vector<int> output; //vector output pentru raspuns
int M, n, x, y, current, next_node, next_index; //plus N definit 100001
in>>n>>M;
bool visited_muchii[500001] = {}; //vector visited pentru muchii
vector < pair <int, int> > evidenta[N]; //in evidenta voi retine pentru fiecare nod: (indice muchie, celalalt capat al muchiei)
for (int i = 0; i < M; i++)
{
in >> x >> y ;
evidenta[x].push_back(make_pair(i,y));
evidenta[y].push_back(make_pair(i,x));
}
// //parcurgere
// for(int i = 1; i <= n; ++i)
// {
// out<<"Pentru nodul i = "<<i<<" avem "<<evidenta[i].size()<<endl;
// for(auto index : evidenta[i])
// out<<index.first<<' '<<i<<' '<<index.second<<endl;
// out<<endl;
// }
for(int i = 0; i < N; ++i)
if(evidenta[i].size() % 2 != 0)
{
out<<"-1";
return;
}
deque <int> dq; //in dq retin nodurile pentru care trebuie sa fac parcurgeri in continuare
dq.push_front(1); //incep de la 1
while(dq.size()!= 0){
current = dq.front();
if(evidenta[current].size() != 0)
{
next_index = evidenta[current][evidenta[current].size()-1].first;
if(!visited_muchii[next_index])
{
visited_muchii[next_index] = true;
next_node = evidenta[current][evidenta[current].size()-1].second;
dq.push_front(next_node);
}
evidenta[current].pop_back();
}
else
{
output.push_back(current);
dq.pop_front();
}
}
// output.pop_back(); //scot de la capat primul nod pe care formatul de afisare nu il prevede
// for(auto node : output) out<<node<<' ';
for(int i = 0; i < output.size() - 1; ++i)
out << output[i] << " ";
// in.close();
// out.close();
}
bool Graph::cuplaj(int x, int (&visited)[N], int (&dr)[N], int (&st)[N], vector<int> (&a)[N])
{
if (visited[x]) return false;
visited[x] = 1;
for (int i = 0; i < a[x].size(); i++)
{
int y = a[x][i];
if (!dr[y])
{
dr[y] = x;
st[x] = y;
return true;
}
}
for (int i = 0; i < a[x].size(); i++)
{
int aux = a[x][i];
if (cuplaj(dr[aux], visited, dr, st, a))
{
st[x] = aux;
dr[aux] = x;
return true;
}
}
return false;
}
void Graph::Solve_Cuplaj() {
ifstream in("cuplaj.in");
ofstream out ("cuplaj.out");
int visited[N], dr[N], st[N];
queue < pair<int, int> > q;
vector <int> a[N];
int u,v,n, m, e, ans;
bool ok = false;
in >> n >> m >> e;
for (int i = 0; i < e; i++)
{
in >> u >> v;
a[u].push_back(v);
}
while (!ok)
{
ok = true;
for (int i = 1; i <= n + m; i++) visited[i] = 0;
for (int i = 1; i <= n; i++)
{
if (!st[i] && cuplaj(i, visited, dr, st, a))
{
ans++;
ok = false;
}
}
}
out << ans << '\n';
for (int i = 1; i <= n; i++)
if (st[i] > 0) out << i << ' ' << st[i] << '\n';
}
void Graph::add_bellman(int x, bool (&in_q)[Nb], int (&q)[Nb+2], int cnt_q[Nb], int &dr)
{
if(in_q[x]) return;
if(dr == Nb + 1) dr = 0;
else dr++;
in_q[x] = true;
cnt_q[x]++;
q[dr] = x;
}
void Graph::Solve_Bellmanford()
{
ifstream in("bellmanford.in");
ofstream out("bellmanford.out");
const int M = 250001;
int n1, n2, x, y, c, dr, n, m, st, ans[Nb], l[Nb], vf[M], next[M], v_cost[M], nr = 0, q[Nb+2], cnt_q[Nb];
bool in_q[Nb];
in>>n>>m;
for(int i=1; i<=m; i++)
{
in>>n1>>n2>>c;
vf[++nr] = n2;
next[nr] = l[n1];
l[n1] = nr;
v_cost[nr] = c;
}
for(int i=1; i<=n; i++) ans[i] = inf;
add_bellman(1, in_q, q, cnt_q, dr);
ans[1] = 0;
while(dr != st-1)
{
if(st == Nb + 2) st = 0;
x = q[st++];
in_q[x] = false;
for(int z = l[x]; z > 0 ; z = next[z])
{
c = v_cost[z];
y = vf[z];
if(ans[x] < ans[y] - c)
{
ans[y] = ans[x] + c;
add_bellman(y, in_q, q, cnt_q, dr);
if(cnt_q[y] == n)
{
out<<"Ciclu negativ!";
return;
}
}
}
}
for(int i = 2; i <= n; i++) out<<ans[i]<<' ';
}
void Graph::Solve_Dijkstra()
{
ifstream in("dijkstra.in");
ofstream out("dijkstra.out");
int n1, n2,x,y,c,vf[Md], nextt[Md],l[Nd],v_cost[Md],nr,n,m,ans[Nd], start = 1;
priority_queue < pair<int,int> > coada;
bool ok[Nd];
in>>n>>m;
for (int i = 1; i <= m ; ++i)
{
in>>n1>>n2>>c;
vf[++nr]=n2;
nextt[nr]=l[n1];
l[n1]=nr;
v_cost[nr]=c;
}
for (int i=1;i<=n;i++) ans[i]=inf;
ans[start] = 0;
coada.push(make_pair(0,start));
while (!coada.empty())
{
while (!coada.empty() && ok[coada.top().second]) coada.pop();
if (coada.empty()) break;
x = coada.top().second;
ok[x]=true;
for (int z = l[x] ; z > 0 ; z = nextt[z])
{
c = v_cost[z];
y = vf[z];
if (ans[x] < ans[y] - c )
{
ans[y] = ans[x] + c ;
coada.push(make_pair(-ans[y] ,y));
}
}
}
for (int i = 2 ; i <= n ; i++)
if (ans[i] != inf) out << ans[i] << ' ';
else out << 0 << ' ';
}
int main()
{
Graph g;
////////////////tema 1
//DFS
// g.Solve_Conexe_DFS();
//BFS
// g.Solve_Min_Dist_BFS();
//Sortaret
// g.Solve_Sortaret();
////////////////tema2
//Apm
// g.Solve_APM();
//disjoint
//g.Solve_Disjoint();
//bellmanford
//g.Solve_Bellmanford();
//dijkstra
g.Solve_Dijkstra();
/////////////////tema3
//darb
//g.Solve_Diametru();
//royfloyd
//g.Solve_Roy();
///////////////tema 4
//eulerian
//g.Solve_Eulerian();
//cuplaj
//g.Solve_Cuplaj();
return 0;
}
//Surse Infoarena: