Pagini recente » Cod sursa (job #1437285) | Cod sursa (job #3318292) | Cod sursa (job #966644) | Cod sursa (job #257485) | Cod sursa (job #3357160)
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
struct Edge {
int to;
int cap;
int flow;
int rev_idx;
int id; // ID-ul original al muchiei din fisier
};
int N, M;
vector<vector<Edge>> adj;
vector<pair<int, int>> original_edges; // Retine capetele pentru verificare finala
vector<int> parent_edge;
vector<int> parent_node;
vector<bool> vis_S, vis_T;
// BFS pentru gasirea drumului de imbunatatire in Edmonds-Karp
bool bfs(int source, int sink) {
fill(parent_node.begin(), parent_node.end(), -1);
queue<int> q;
q.push(source);
parent_node[source] = source;
while (!q.empty()) {
int u = q.front();
q.pop();
if (u == sink) return true;
for (int i = 0; i < adj[u].size(); ++i) {
Edge& e = adj[u][i];
if (parent_node[e.to] == -1 && e.cap - e.flow > 0) {
parent_node[e.to] = u;
parent_edge[e.to] = i;
q.push(e.to);
}
}
}
return false;
}
// Algoritmul Edmonds-Karp pentru flux maxim
void max_flow(int source, int sink) {
parent_edge.assign(N + 1, -1);
parent_node.assign(N + 1, -1);
while (bfs(source, sink)) {
int push_flow = 2e9;
// Gasim capacitatea reziduala minima pe drum
for (int v = sink; v != source; v = parent_node[v]) {
int u = parent_node[v];
int idx = parent_edge[v];
push_flow = min(push_flow, adj[u][idx].cap - adj[u][idx].flow);
}
// Actualizam fluxul in retea
for (int v = sink; v != source; v = parent_node[v]) {
int u = parent_node[v];
int idx = parent_edge[v];
int rev_idx = adj[u][idx].rev_idx;
adj[u][idx].flow += push_flow;
adj[v][rev_idx].flow -= push_flow;
}
}
}
// BFS din sursa pentru a gasi componentele accesibile in graful rezidual
void bfs_S(int source) {
vis_S.assign(N + 1, false);
queue<int> q;
q.push(source);
vis_S[source] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (const auto& e : adj[u]) {
if (!vis_S[e.to] && e.cap - e.flow > 0) {
vis_S[e.to] = true;
q.push(e.to);
}
}
}
}
// BFS invers din destinatie pentru a gasi nodurile care pot ajunge la sink
void bfs_T(int sink) {
vis_T.assign(N + 1, false);
queue<int> q;
q.push(sink);
vis_T[sink] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (const auto& e : adj[u]) {
// Mergem invers: daca muchia de la e.to la u are capacitate reziduala
// Inseamna ca e.to poate trimite flux catre u.
// In codul nostru, e.to -> u are fluxul e.flow inversat in arcul pereche.
int rev_idx = e.rev_idx;
if (!vis_T[e.to] && adj[e.to][rev_idx].cap - adj[e.to][rev_idx].flow > 0) {
vis_T[e.to] = true;
q.push(e.to);
}
}
}
}
int main() {
ifstream fin("critice.in");
ofstream fout("critice.out");
if (!fin) return 0;
fin >> N >> M;
adj.resize(N + 1);
original_edges.resize(M + 1);
for (int i = 1; i <= M; ++i) {
int u, v, c;
fin >> u >> v >> c;
original_edges[i] = { u, v };
// Adaugam arcul u -> v
Edge a = { v, c, 0, (int)adj[v].size(), i };
// Adaugam arcul v -> u (deoarece graful este neorientat)
Edge b = { u, c, 0, (int)adj[u].size(), i };
adj[u].push_back(a);
adj[v].push_back(b);
}
// Pasul 1: Calculam fluxul maxim de la 1 la N
max_flow(1, N);
// Pasul 2: Identificam multimile S si T in graful rezidual
bfs_S(1);
bfs_T(N);
// Pasul 3: Gasim muchiile critice
vector<int> critical_edges;
for (int i = 1; i <= M; ++i) {
int u = original_edges[i].first;
int v = original_edges[i].second;
// O muchie este critica daca un capat este in S, celalalt in T
// si este complet saturata pe acea directie.
if ((vis_S[u] && vis_T[v]) || (vis_S[v] && vis_T[u])) {
critical_edges.push_back(i);
}
}
// Sortam indicii descriptorilor (sunt deja sortati deoarece i creste de la 1 la M)
fout << critical_edges.size() << "\n";
for (int id : critical_edges) {
fout << id << "\n";
}
return 0;
}