Pagini recente » Cod sursa (job #707830) | Cod sursa (job #1933575) | Cod sursa (job #3189226) | Cod sursa (job #2776314) | Cod sursa (job #2792080)
//
// main.cpp
// Componente tare conexe
//
// Created by Mara Dascalu on 31/10/2021.
//
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
#include <bits/stdc++.h>
#include <map>
#include <list>
#include <set>
using namespace std;
ifstream input("ctc.in");
ofstream output("ctc.out");
class Graph
{
int nodes, edges;
vector<int> adj[100010] ;
int cost[1001];
queue<int> queue_bfs;
int level[100010] = {0};
int low_level[100010] = {0};
stack<pair<int, int>> component_node;
vector<int> vec_scc[100010];
public:
bool visited[100010] = {0};
vector<int> bcc[100010]; //vectorul care stocheaza componentele biconexe
int current = 0;
void set_no_nodes(int n) {nodes = n;}
int get_no_nodes() {return nodes;}
void set_no_edges(int n) {edges = n;}
int get_no_edges() {return edges;}
void addEdge_dg ()
{
int no_nodes, no_edges;
input>>no_nodes>>no_edges;
set_no_nodes(no_nodes);
int node1, node2;
for(int i = 0 ; i < no_edges; i++)
{
input>>node1>>node2;
adj[node1].push_back(node2);
}
}
void addEdge_ug ()
{
int no_nodes, no_edges;
input>>no_nodes>>no_edges;
int node1, node2;
for(int i = 0 ; i < no_edges; i++)
{
input>>node1>>node2;
adj[node1].push_back(node2);
adj[node2].push_back(node1);
}
}
void DFS(int node)
{
visited[node] = 1;
output<<node<<" ";
for (int i = 0; i < adj[node].size(); i++)
if( !visited[adj[node][i]])
DFS(adj[node][i]);
}
void afis_adj(int node){
for (int i = 0; i < adj[node].size(); i++)
cout<<adj[node][i]<<" ";
}
void BFS (int node)
{
memset(cost, -1, sizeof(cost));
visited[node] = 1; //marchez nodul curent ca vizitat
queue_bfs.push(node);
cost[node] = 0;
while (!queue_bfs.empty()) {
node = queue_bfs.front(); //iau nodul din varful cozii
queue_bfs.pop();
for (int i = 0; i < adj[node].size(); i++) //parcurg toti vecinii sai
if ( !visited[adj[node][i]]) //daca sunt nevizitati
{
visited[adj[node][i]] = 1; //ii marchez ca vizitati
queue_bfs.push(adj[node][i]); //ii adaug in coada
cost[adj[node][i]] = cost[node] + 1; //calculez costul raportat la "parintele" sau
}
}
}
void out_cost (int no)
{
for (int i = 1; i <= no; i++)
output<<cost[i]<<" ";
}
void DFS(int node, int parent)
{
visited[node] = 1;
level[node] = level[parent] + 1;
low_level[node] = level[node];
int child;
int dim = adj[node].size();
for ( int i = 0; i< dim ; i++)
{
child = adj[node][i];
if (child != parent)
{
if (visited[child] == true) //daca fiul sau a fost deja parcurs si nu este tatal nodului curent, muchia (fiu,nod) este muchie de intoarcere
{
//cout<<"true "<<node<<" "<<*iter<<" "<<level[*iter]<<"\n";
if(level[child] < low_level[node])low_level[node] = level[child]; //actualizam valoarea low_level[nod] daca fiul sau se afla mai sus decat el (p[t ca avem muchie de intoarcere
}
else //daca fiul sau nu a fost inca parcurs, continuam DFS din fiu
{
component_node.push({node, child});
//cout<<"inainte de dfs"<<node<<" "<<*iter<<" "<<level[*iter]<<"\n";
DFS(child, node);
//cout<<"dupa dfs"<<*iter<<" "<<level[*iter]<<"\n";
if (low_level[child] < low_level[node])
low_level[node] = low_level[child]; //daca la intoarcerea din apel fiul are un nivel de intoarcere mai mic decat al nodului, actualizam low_level[node]
if (low_level[child] >= level[node])
{
while( component_node.top().first != node)
{
bcc[current].push_back(component_node.top().second);
component_node.pop();
}
bcc[current].push_back(component_node.top().second);
bcc[current].push_back(component_node.top().first);
component_node.pop();
//bcc[current].push_back(node);
current++;
}
}
}
}
}
void sccUtil (int node, int disc[], int low[], stack<int> *st, bool stackMember[])
{
static int time = 0;
//initializare disc si low pentru nodul curent
disc[node] = low[node] = time++;
st->push(node);
stackMember[node] = true;
//parcurgem toti vecinii lui node
for (int i = 0; i < adj[node].size(); i++)
{
int adj_node = adj[node][i];
if (!disc[adj_node]) //daca vecinul nu a fost vizitat inca
{
sccUtil(adj_node, disc, low, st, stackMember);
low[node] = min(low[node], low[adj_node]); //verificam daca subarborele care are drep radacina adj_node are un drum catre un stramos al lui node
}
else if (stackMember)
{
low[node] = min(low[node], disc[adj_node]); //facem update daca avem muchie de intoarcere
}
}
int extractedNode = 0;
if (low[node] == disc[node]) //conditia ca un nod sa fie radacina unei componente tare conexe
{
while (st->top() != node) {
extractedNode = (int) st->top();
st->pop();
// cout<<extractedNode<<" ";
vec_scc[current].push_back(extractedNode);
stackMember[extractedNode] = false;
}
extractedNode = st->top();
st->pop();
// cout<<extractedNode<<"\n";
vec_scc[current].push_back(extractedNode);
sort(vec_scc[current].begin(), vec_scc[current].end());
stackMember[extractedNode] = false;
current++;
}
}
void scc()
{
int dim = get_no_nodes();
int *disc = new int[dim]; //memoreaza timpul de descoperire al fiecarui nod
int *low = new int[dim]; //memoreaza timpul de descoperire minim care poate fi accesat din subarborele care are radacina in fiecare nod
bool *stackMember = new bool[dim]; //pentru verificarea mai rapida daca un nod este sau nu in stiva
stack<int> *st = new stack<int>(); //pentru stocarea compo\ conexe
for (int i = 0; i < dim ; i++)
{
disc[i] = low[i] = 0;
stackMember[i] = false;
}
//apelam recursiv sccUtil pentru gasirea comp tare conexe
for (int i = 1; i <= dim; i++)
if(!disc[i])
sccUtil(i, disc, low, st, stackMember);
}
void output_scc ()
{
output<<current<<"\n";
for (int i = current - 1; i >= 0 ; i--)
{
for (int j = 0; j < vec_scc[i].size(); j++)
output<<vec_scc[i][j]<<" ";
output<<"\n";
}
}
}g;
int main(int argc, const char * argv[]) {
g.addEdge_dg();
g.scc();
g.output_scc();
return 0;
}