Pagini recente » Istoria paginii runda/incepator./clasament | Cod sursa (job #2904407) | Cod sursa (job #2360075) | Cod sursa (job #1858945) | Cod sursa (job #2925769)
//Complexitate: O(n+m) din cauza dfs-ului
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast")
#pragma GCC optimize ("unroll-loops")
#include <bits/stdc++.h>
#include <fstream>
using namespace std;
std::ifstream f("ctc.in");
ofstream g("ctc.out");
void dfs(int &start, vector<bool> & vizitat,vector<vector<int>> &lista,vector<bool> &tarjan, vector<int> &index,vector<int> & low,int &nr,stack<int> &stack,vector<vector<int>> &sol,int &nrCTC)
{
stack.push(start);
vizitat[start] = true;
tarjan[start] = true;
index[start] = low[start] = nr;
nr++;
//pun nodul curent pe stiva, il nodez in tarjan ca fiind pe stiva, in vectorul vizitat ca fiind vizitat, iar index este egal cu low care primeste nr(al catelea element
//este parcurs pe dfs) deoarece deocamdata cel mai adanc nod in care ne putem duce este el insusi
for(int i = 0;i<lista[start].size();i++)
{if(vizitat[lista[start][i]] == false)
dfs(lista[start][i], vizitat, lista,tarjan,index,low,nr,stack,sol,nrCTC);
//vecinii nodului curent ii pun pe stiva programului
if(tarjan[lista[start][i]] == true)
low[start] = min(low[start],low[lista[start][i]]);}
//cel mai adanc punct al nodului curent poate fi unul dintre vecinii lui sau un nod conectat la unul dintre vecinii lui s.a.
if(index[start] == low[start])
//daca unui nod i-au fost parcursi toti vecinii inseamna ca nu are unde sa se duca mai departe, si daca cel mai indepartat punct in care poate sa ajunga
//este chiar el insusi inseamna ca, parcurcand stiva declarata pana la el avem o ctc
{
vector<int>v;
int elementDinStiva = stack.top();
v.push_back(elementDinStiva);
while (elementDinStiva != start)
{
tarjan[elementDinStiva] = false;
//il marcam ca nu mai fiind pe stiva
low[elementDinStiva] = index[start];
//iar cel mai indepartat nod primeste indexul nodului curent(start) deoare face parte din aceeasi ctc
stack.pop();
elementDinStiva = stack.top();
v.push_back(elementDinStiva);
}
tarjan[start] = false;
stack.pop();
sol.push_back(v);
nrCTC++;
//punem ctc in vectorul de solutii si incrementam numarul de solutii
}
}
int main(){
int n,m,i,a,b;
vector<vector<int>> lista;
f>>n>>m;
for(i = 0;i<=n;i++)
lista.push_back({});
while (f>>a>>b)
{
lista[a].push_back(b);
}
stack<int> stack;
//stiva pentru pastrarea nodurilor din elementele conexe
vector<bool> vizitat(n+1,false);
//vector de vizitat pentru nodurile grafurior
vector<bool> stivaTarjan(n+1,false);
//daca un nod se afla pe stiva declarata anterior avem true, altfel avem false
vector<int> index(n+1,0);
//vector pentru a pastra al catelea nod este parcurs prin dfs-ul nostru
vector<int> low(n+1,0);
//vector pentru fiecare nod pentru a afla cat de adancime se poate duce un nod
int nr = 1,nrCTC = 0;
//nr este pentru a i oferii un index fiecarui nod parcurs cu dfs, iar nrCTC este numarul de componente conexe
vector<vector<int>> sol;
//sol este vectorul de solutii
for(int i = 1;i<=n;i++)
if(vizitat[i] == false)
dfs(i,vizitat,lista,stivaTarjan,index,low,nr,stack,sol,nrCTC);
//cat timp pot incepe de undeva apelez dfs-ul pe nodul respectiv
g<<nrCTC<<endl;
for(auto j: sol) {
for (int k = 0; k < j.size(); k++)
g << j[k] << ' ';
g << endl;
}
f.close();g.close();
//afisez solutia
return 0;
}