Cod sursa(job #3375004)

Utilizator teoo.mnlManolescu Teodor teoo.mnl Data 9 noiembrie 2026 22:24:25
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 19.89 kb
//-------------------------------------------------------------
// // sate

// #include <iostream>
// #include <fstream>
// #include <vector>
// #include <queue>

// using namespace std;

// const int MAXN = 30005;

// // Graful va reține perechi de tipul {vecin, cost_muchie}
// vector<pair<int, int>> adj[MAXN];
// bool vizitat[MAXN];
// int dist[MAXN];

// int main() {
//     ifstream fin("sate.in");
//     ofstream fout("sate.out");

//     int N, M, X, Y;
//     fin >> N >> M >> X >> Y;

//     for (int k = 0; k < M; ++k) {
//         int u, v, d;
//         fin >> u >> v >> d;
        
//         // Adăugăm muchia directă (cost pozitiv)
//         adj[u].push_back({v, d});
//         // Adăugăm muchia inversă (cost negativ)
//         adj[v].push_back({u, -d});
//     }

//     // Parcurgere BFS plecând din X
//     queue<int> q;
//     q.push(X);
//     vizitat[X] = true;
//     dist[X] = 0;

//     while (!q.empty()) {
//         int u = q.front();
//         q.pop();

//         // Dacă am ajuns la satul căutat, ne putem opri
//         if (u == Y) {
//             break;
//         }

//         for (auto muchie : adj[u]) {
//             int v = muchie.first;
//             int cost = muchie.second;

//             if (!vizitat[v]) {
//                 vizitat[v] = true;
//                 dist[v] = dist[u] + cost;
//                 q.push(v);
//             }
//         }
//     }

//     fout << dist[Y] << "\n";

//     return 0;
// }




//-------------------------------------------------------------
// // alice 2

// #include <iostream>
// #include <fstream>
// #include <vector>
// #include <string>
// #include <queue>

// using namespace std;

// int main() {
//     ifstream fin("alice2.in");
//     ofstream fout("alice2.out");

//     string s;
//     fin >> s;
//     int n = s.length();

//     // Caz de bază: cuvânt de o literă
//     if (n <= 1) {
//         fout << 0 << "\n";
//         return 0;
//     }

//     vector<int> prev_pos(n, -1);
//     vector<int> next_pos(n, -1);
    
//     // Precalculare salturi la stânga
//     vector<int> last_seen(26, -1);
//     for (int i = 0; i < n; ++i) {
//         int char_idx = s[i] - 'a';
//         if (last_seen[char_idx] != -1) {
//             prev_pos[i] = last_seen[char_idx];
//         }
//         last_seen[char_idx] = i;
//     }

//     // Precalculare salturi la dreapta
//     vector<int> first_seen(26, -1);
//     for (int i = n - 1; i >= 0; --i) {
//         int char_idx = s[i] - 'a';
//         if (first_seen[char_idx] != -1) {
//             next_pos[i] = first_seen[char_idx];
//         }
//         first_seen[char_idx] = i;
//     }

//     // BFS pentru drum minim
//     vector<int> dist(n, -1);
//     queue<int> q;

//     q.push(0);
//     dist[0] = 0;

//     while (!q.empty()) {
//         int u = q.front();
//         q.pop();

//         // Dacă am ajuns la destinație, ne putem opri direct
//         if (u == n - 1) {
//             fout << dist[u] << "\n";
//             return 0;
//         }

//         // Construim lista de vecini posibili
//         vector<int> vecini;
//         if (u > 0) vecini.push_back(u - 1);
//         if (u < n - 1) vecini.push_back(u + 1);
//         if (prev_pos[u] != -1) vecini.push_back(prev_pos[u]);
//         if (next_pos[u] != -1) vecini.push_back(next_pos[u]);

//         // Vizităm vecinii neexplorați
//         for (int v : vecini) {
//             if (dist[v] == -1) {
//                 dist[v] = dist[u] + 1;
//                 q.push(v);
//             }
//         }
//     }

//     return 0;
// }




// //-------------------------------------------------------------
// // EasyGraph

// #include <iostream>
// #include <fstream>
// #include <vector>
// #include <algorithm>

// using namespace std;

// const int MAXN = 15005;
// long long v[MAXN];
// vector<int> adj[MAXN];
// long long dp[MAXN];
// bool vizitat[MAXN];
// long long ans_max;

// // Funcția DFS care calculează DP-ul
// void dfs(int u) {
//     vizitat[u] = true;
    
//     long long max_fiu = 0; // Inițializăm cu 0 pentru cazul în care ne oprim în u
    
//     for (int w : adj[u]) {
//         if (!vizitat[w]) {
//             dfs(w);
//         }
//         // După ce vecinul a fost calculat (sau era deja calculat), vedem dacă e profitabil
//         max_fiu = max(max_fiu, dp[w]);
//     }
    
//     // Suma maximă plecând din u este valoarea lui u + cel mai bun drum prin fii
//     dp[u] = v[u] + max_fiu;
    
//     // Actualizăm răspunsul global
//     ans_max = max(ans_max, dp[u]);
// }

// void rezolva_test(ifstream& fin, ofstream& fout) {
//     int N, M;
//     fin >> N >> M;
    
//     for (int i = 1; i <= N; ++i) {
//         fin >> v[i];
//         adj[i].clear();       // Resetăm graful pentru noul test
//         vizitat[i] = false;   // Resetăm starea de vizitare
//     }
    
//     for (int i = 0; i < M; ++i) {
//         int x, y;
//         fin >> x >> y;
//         adj[x].push_back(y);
//     }
    
//     ans_max = -2e18; // Inițializăm cu o valoare extrem de mică (nu 0!)
    
//     // Graful poate fi format din mai multe componente conexe, 
//     // deci pornim DFS-ul din toate nodurile nevizitate.
//     for (int i = 1; i <= N; ++i) {
//         if (!vizitat[i]) {
//             dfs(i);
//         }
//     }
    
//     fout << ans_max << "\n";
// }

// int main() {
//     ifstream fin("easygraph.in");
//     ofstream fout("easygraph.out");
    
//     int T;
//     if (fin >> T) {
//         while (T--) {
//             rezolva_test(fin, fout);
//         }
//     }
    
//     return 0;
// }





// //-------------------------------------------------------------
// // Path

// #include <iostream>
// #include <fstream>
// #include <vector>
// #include <string>
// #include <algorithm>

// using namespace std;

// const long long INF = 2000000005LL; // Un pic mai mare decât K-ul maxim permis

// // Funcții de conversie pentru a respecta ordinea: mici apoi mari
// int char_to_idx(char c) {
//     if (c >= 'a' && c <= 'z') return c - 'a';
//     return c - 'A' + 26;
// }

// char idx_to_char(int idx) {
//     if (idx < 26) return 'a' + idx;
//     return 'A' + idx - 26;
// }

// vector<int> adj[52];
// bool prezent[52];
// long long max_len[52];
// long long cnt[52];
// bool vizitat[52];

// void dfs(int u) {
//     if (vizitat[u]) return;
//     vizitat[u] = true;
    
//     max_len[u] = 0;
//     cnt[u] = 1; // Un drum de lungime 0 (nodul în sine)
    
//     long long mx = 0;
//     // Găsim lungimea maximă
//     for (int v : adj[u]) {
//         dfs(v);
//         mx = max(mx, 1 + max_len[v]);
//     }
    
//     // Calculăm numărul de drumuri care au această lungime maximă
//     if (mx > 0) {
//         max_len[u] = mx;
//         long long c = 0;
//         for (int v : adj[u]) {
//             if (1 + max_len[v] == mx) {
//                 c += cnt[v];
//                 if (c > INF) c = INF; // Plafonare pentru a evita overflow
//             }
//         }
//         cnt[u] = c;
//     }
// }

// int main() {
//     ifstream fin("path.in");
//     ofstream fout("path.out");
    
//     int N, M;
//     long long K;
//     fin >> N >> M >> K;
    
//     for (int i = 0; i < M; ++i) {
//         char c1, c2;
//         fin >> c1 >> c2;
//         int u = char_to_idx(c1);
//         int v = char_to_idx(c2);
//         adj[u].push_back(v);
//         prezent[u] = prezent[v] = true;
//     }
    
//     // Sortăm vecinii pentru a-i parcurge mereu în ordine lexicografică
//     for (int i = 0; i < 52; ++i) {
//         if (!adj[i].empty()) {
//             sort(adj[i].begin(), adj[i].end());
//         }
//     }
    
//     // Pas 1: Calculăm DP-urile pentru toate nodurile
//     long long L_max = 0;
//     for (int i = 0; i < 52; ++i) {
//         if (prezent[i]) {
//             dfs(i);
//             L_max = max(L_max, max_len[i]);
//         }
//     }
    
//     // Pas 2: Colectăm nodurile de start valide (care pot forma L_max)
//     vector<int> starts;
//     for (int i = 0; i < 52; ++i) {
//         if (prezent[i] && max_len[i] == L_max) {
//             starts.push_back(i);
//         }
//     }
    
//     // Pas 3: Găsim nodul de start pentru al K-lea drum
//     int curr = -1;
//     for (int u : starts) {
//         if (K <= cnt[u]) {
//             curr = u;
//             break;
//         } else {
//             K -= cnt[u];
//         }
//     }
    
//     string ans = "";
//     ans += idx_to_char(curr);
//     long long current_len = L_max;
    
//     // Pas 4: Avansăm nod cu nod pentru a construi drumul
//     while (current_len > 0) {
//         for (int v : adj[curr]) {
//             // Ne interesează doar vecinii care mențin lungimea maximă rămasă
//             if (max_len[v] == current_len - 1) {
//                 if (K <= cnt[v]) {
//                     curr = v;
//                     ans += idx_to_char(curr);
//                     current_len--;
//                     break; // Am găsit următorul nod, reluăm procesul din el
//                 } else {
//                     K -= cnt[v];
//                 }
//             }
//         }
//     }
    
//     fout << ans << "\n";
    
//     return 0;
// }




// //-------------------------------------------------------------
// Freakadebunic

// #include <iostream>
// #include <fstream>
// #include <vector>
// #include <algorithm>

// using namespace std;

// const int MAXN = 100005;

// vector<int> adj[MAXN];
// bool are_trupa[MAXN];
// int parinte[MAXN];
// int nr_trupe_subarbore[MAXN];
// bool vizitat[MAXN];

// int main() {
//     ifstream fin("freakadebunic.in");
//     ofstream fout("freakadebunic.out");

//     int N, K;
//     if (!(fin >> N >> K)) return 0;

//     for (int i = 0; i < K; ++i) {
//         int x;
//         fin >> x;
//         are_trupa[x] = true;
//     }

//     for (int i = 0; i < N - 1; ++i) {
//         int u, v;
//         fin >> u >> v;
//         adj[u].push_back(v);
//         adj[v].push_back(u);
//     }

//     // 1. Parcurgere BFS pentru a ordona nodurile de sus în jos (fără recursivitate!)
//     vector<int> ordine;
//     ordine.reserve(N);
    
//     ordine.push_back(1);
//     vizitat[1] = true;

//     for (int i = 0; i < (int)ordine.size(); ++i) {
//         int u = ordine[i];
//         for (int v : adj[u]) {
//             if (!vizitat[v]) {
//                 vizitat[v] = true;
//                 parinte[v] = u;
//                 ordine.push_back(v);
//             }
//         }
//     }

//     vector<int> devreme;

//     // 2. Parcurgem nodurile invers (de la frunze spre rădăcină)
//     for (int i = N - 1; i >= 0; --i) {
//         int u = ordine[i];
//         int surse = 0;

//         // Dacă e o trupă chiar în nodul u, e o primă sursă
//         if (are_trupa[u]) {
//             surse++;
//             nr_trupe_subarbore[u]++;
//         }

//         // Verificăm fiii lui u
//         for (int v : adj[u]) {
//             if (v != parinte[u]) {
//                 if (nr_trupe_subarbore[v] > 0) {
//                     surse++; // Acest fiu aduce cel puțin o trupă din subarborele său
//                     nr_trupe_subarbore[u] += nr_trupe_subarbore[v];
//                 }
//             }
//         }

//         // Dacă se întâlnesc trupe din cel puțin 2 direcții/surse, u este nod "devreme"
//         if (surse >= 2) {
//             devreme.push_back(u);
//         }
//     }

//     // Sortăm crescător nodurile găsite
//     sort(devreme.begin(), devreme.end());

//     // Afișare
//     fout << devreme.size() << "\n";
//     for (int u : devreme) {
//         fout << u << " ";
//     }
//     fout << "\n";

//     return 0;
// }





// //-------------------------------------------------------------
// // pamant


// #include <iostream>
// #include <fstream>
// #include <vector>
// #include <algorithm>

// using namespace std;

// const int MAXN = 100005;

// vector<int> adj[MAXN];
// int tin[MAXN], low[MAXN];
// int timer = 0;
// bool vizitat[MAXN];
// bool este_vulnerabil[MAXN];

// vector<int> coduri_echipe;
// vector<int> copii_vulnerabili;

// int minim_echipa_curenta;

// // Parcurgerea DFS care calculează și componentele conexe și punctele de articulație
// void dfs(int u, int p = -1) {
//     vizitat[u] = true;
//     tin[u] = low[u] = ++timer;
    
//     // Actualizăm codul (nodul minim) pentru echipa curentă
//     minim_echipa_curenta = min(minim_echipa_curenta, u);
    
//     int numar_fii_dfs = 0;
    
//     for (int v : adj[u]) {
//         if (v == p) continue; // Nu ne întoarcem pe muchia din care abia am venit
        
//         if (vizitat[v]) {
//             // Am dat de o muchie de întoarcere
//             low[u] = min(low[u], tin[v]);
//         } else {
//             // Este un fiu nou în arborele DFS
//             numar_fii_dfs++;
//             dfs(v, u);
            
//             // Când ne întoarcem din fiu, actualizăm valoarea low a părintelui
//             low[u] = min(low[u], low[v]);
            
//             // Verificăm condiția de punct de articulație pentru un nod care NU e rădăcină
//             if (p != -1 && low[v] >= tin[u]) {
//                 este_vulnerabil[u] = true;
//             }
//         }
//     }
    
//     // Condiția de punct de articulație pentru rădăcina arborelui DFS
//     if (p == -1 && numar_fii_dfs > 1) {
//         este_vulnerabil[u] = true;
//     }
// }

// int main() {
//     ifstream fin("pamant.in");
//     ofstream fout("pamant.out");
    
//     int n, m;
//     if (!(fin >> n >> m)) return 0;
    
//     for (int i = 0; i < m; ++i) {
//         int u, v;
//         fin >> u >> v;
//         adj[u].push_back(v);
//         adj[v].push_back(u);
//     }
    
//     // Identificăm componentele conexe (Echipele)
//     for (int i = 1; i <= n; ++i) {
//         if (!vizitat[i]) {
//             minim_echipa_curenta = i; // Inițializăm cu nodul de start
//             dfs(i, -1);
//             coduri_echipe.push_back(minim_echipa_curenta);
//         }
//     }
    
//     // Colectăm copiii vulnerabili găsiți de DFS
//     for (int i = 1; i <= n; ++i) {
//         if (este_vulnerabil[i]) {
//             copii_vulnerabili.push_back(i);
//         }
//     }
    
//     // Sortăm listele pentru afișarea cerută în enunț
//     sort(coduri_echipe.begin(), coduri_echipe.end());
//     // (copii_vulnerabili sunt deja în ordine crescătoare, dar e o practică bună)
//     sort(copii_vulnerabili.begin(), copii_vulnerabili.end()); 
    
//     // Afișăm cele 4 linii de output
//     fout << coduri_echipe.size() << "\n";
//     for (int cod : coduri_echipe) {
//         fout << cod << " ";
//     }
//     fout << "\n";
    
//     fout << copii_vulnerabili.size() << "\n";
//     for (int copil : copii_vulnerabili) {
//         fout << copil << " ";
//     }
//     fout << "\n";
    
//     return 0;
// }



// //-------------------------------------------------------------
// // Componente biconexe


// #include <iostream>
// #include <fstream>
// #include <vector>
// #include <stack>
// #include <algorithm>

// using namespace std;

// const int MAXN = 100005;

// vector<int> adj[MAXN];
// int tin[MAXN], low[MAXN];
// int timer = 0;
// stack<int> st;

// // Reținem componentele într-un vector de vectori pentru a le număra ușor la final
// vector<vector<int>> bccs;

// void dfs(int u, int p = -1) {
//     tin[u] = low[u] = ++timer;
//     st.push(u); // Punem nodul curent în stivă

//     for (int v : adj[u]) {
//         if (v == p) continue; // Ignorăm muchia de întoarcere la părintele direct

//         if (tin[v]) { // Nod deja vizitat -> muchie de întoarcere (back edge)
//             low[u] = min(low[u], tin[v]);
//         } else { // Nod nevizitat -> avansăm în DFS
//             dfs(v, u);
//             low[u] = min(low[u], low[v]);

//             // Verificăm condiția de punct de articulație
//             if (low[v] >= tin[u]) {
//                 vector<int> current_bcc;
//                 int extras;
                
//                 // Scoatem din stivă tot subarborele lui v care a rămas izolat
//                 do {
//                     extras = st.top();
//                     st.pop();
//                     current_bcc.push_back(extras);
//                 } while (extras != v);
                
//                 // Adăugăm și nodul u (punctul de articulație) în componentă, 
//                 // dar FĂRĂ a-l scoate definitiv din stiva globală!
//                 current_bcc.push_back(u);
                
//                 bccs.push_back(current_bcc);
//             }
//         }
//     }
// }

// int main() {
//     ifstream fin("biconex.in");
//     ofstream fout("biconex.out");

//     int N, M;
//     if (!(fin >> N >> M)) return 0;

//     for (int i = 0; i < M; ++i) {
//         int u, v;
//         fin >> u >> v;
//         adj[u].push_back(v);
//         adj[v].push_back(u);
//     }

//     // Graful poate fi neconex, deci pornim DFS din fiecare componentă conexă izolată
//     for (int i = 1; i <= N; ++i) {
//         if (!tin[i]) {
//             dfs(i);
//         }
//     }

//     // Afișăm rezultatele
//     fout << bccs.size() << "\n";
//     for (const auto& comp : bccs) {
//         for (int nod : comp) {
//             fout << nod << " ";
//         }
//         fout << "\n";
//     }

//     return 0;
// }




// //-------------------------------------------------------------
// // Componente biconexe


#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

const int MAXN = 100005;

vector<int> adj[MAXN];
int tin[MAXN], low[MAXN];
bool in_stack[MAXN];
int timer = 0;
stack<int> st;

vector<vector<int>> ctc;

void dfs(int u) {
    tin[u] = low[u] = ++timer;
    st.push(u);
    in_stack[u] = true;

    for (int v : adj[u]) {
        if (!tin[v]) {
            // Nod nevizitat
            dfs(v);
            low[u] = min(low[u], low[v]);
        } else if (in_stack[v]) {
            // Nod vizitat și aflat în stivă (muchie de întoarcere validă)
            low[u] = min(low[u], tin[v]);
        }
        // Dacă e vizitat dar NU e în stivă (cross-edge), îl ignorăm complet.
    }

    // Am terminat de explorat vecinii. Verificăm dacă u este rădăcina unei CTC.
    if (low[u] == tin[u]) {
        vector<int> componenta_curenta;
        int extras;
        
        // Extragem din stivă până dăm de u
        do {
            extras = st.top();
            st.pop();
            in_stack[extras] = false; // Îl marcăm ca scos
            componenta_curenta.push_back(extras);
        } while (extras != u);
        
        ctc.push_back(componenta_curenta);
    }
}

int main() {
    ifstream fin("ctc.in");
    ofstream fout("ctc.out");

    int N, M;
    if (!(fin >> N >> M)) return 0;

    for (int i = 0; i < M; ++i) {
        int u, v;
        fin >> u >> v;
        adj[u].push_back(v); // Graf orientat, deci adăugăm doar u -> v
    }

    // Graful poate fi format din mai multe bucăți disjuncte
    for (int i = 1; i <= N; ++i) {
        if (!tin[i]) {
            dfs(i);
        }
    }

    // Afișarea rezultatelor
    fout << ctc.size() << "\n";
    for (const auto& comp : ctc) {
        for (int nod : comp) {
            fout << nod << " ";
        }
        fout << "\n";
    }

    return 0;
}