Pagini recente » Cod sursa (job #1282188) | Cod sursa (job #3281936) | Cod sursa (job #1001275) | infoarena - comunitate informatica, concursuri de programare | Cod sursa (job #2694544)
//package critice;
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
Scanner scn = new Scanner(new FileInputStream("critice.in"));
PrintWriter writer = new PrintWriter(new FileOutputStream("critice.out"));
int n = scn.nextInt();
int m = scn.nextInt();
List<Node> nodes = new ArrayList<>();
for (int i = 1; i <= n; i++) {
Node node = new Node(i);
nodes.add(node);
}
Edge[] edgesByIndex = new Edge[m + 1];
// add the edges
for (int i = 1; i <= m; i++) {
int fromId = scn.nextInt();
int toId = scn.nextInt();
int cap = scn.nextInt();
Node from = nodes.get(fromId - 1);
Node to = nodes.get(toId - 1);
Edge e = from.addEdge(to, 0, cap);
to.addEdge(from, 0, cap);
edgesByIndex[i] = e;
}
// create the graph
Graph g = new Graph(nodes, nodes.get(0), nodes.get(n - 1));
// compute the maxmum flow
g.maximizeFlow();
// find the bottleneck edges
Set<Node> visited = new HashSet<>();
DFS(g.source, visited);
// output the critical edges
List<Integer> criticalEdges = new ArrayList<>();
for(int i = 1; i <= m; i++) {
if(visited.contains(edgesByIndex[i].from) && !visited.contains(edgesByIndex[i].to))
criticalEdges.add(i);
else if(visited.contains(edgesByIndex[i].to) && !visited.contains(edgesByIndex[i].from))
criticalEdges.add(i);
}
writer.println(criticalEdges.size());
for (Integer index : criticalEdges) {
writer.println(index);
}
writer.close();
scn.close();
}
private static void DFS(Node current, Set<Node> visited) {
if (visited.contains(current))
return;
visited.add(current);
for (Edge e : current.edges) {
int bottleneck = e.cap - e.flow;
// the path is blocked
if (bottleneck <= 0)
continue;
DFS(e.to, visited);
}
}
}
class Node {
List<Edge> edges;
int id;
public Node(int id) {
this.id = id;
edges = new ArrayList<>();
}
public Edge addEdge(Node to, int flow, int cap) {
Edge poz = new Edge(this, to, flow, cap, false);
Edge neg = new Edge(to, this, cap - flow, cap, true);
poz.counterpart = neg;
neg.counterpart = poz;
edges.add(poz);
to.edges.add(neg);
return poz;
}
}
class Edge {
Node from;
Node to;
int cap;
int flow;
Edge counterpart;
boolean backward;
public Edge(Node from, Node to, int flow, int cap, boolean backward) {
this.from = from;
this.to = to;
this.flow = flow;
this.cap = cap;
this.backward = backward;
}
void setFlow(int newFlow) {
if (newFlow > cap)
throw new IllegalArgumentException("Overflow!");
flow = newFlow;
counterpart.flow = cap - newFlow;
}
}
class Graph {
List<Node> nodes;
Node source;
Node sink;
public Graph(List<Node> nodes, Node source, Node sink) {
this.nodes = nodes;
this.source = source;
this.sink = sink;
}
public int getFlow() {
int flow = 0;
for (Edge e : source.edges) {
if (e.backward)
continue;
flow += e.flow;
}
return flow;
}
public void maximizeFlow() {
while(true) {
if (!augmentPath())
break;
}
}
private boolean augmentPath() {
List<Edge> path = findAugmentingPathBFS();
if (path == null)
return false;
// find the bottleneck
int bottleneck = Integer.MAX_VALUE;
for (Edge e : path) {
bottleneck = Math.min(bottleneck, e.cap - e.flow);
}
// update the path
for (Edge e : path) {
e.setFlow(e.flow + bottleneck);
}
return true;
}
private List<Edge> findAugmentingPathBFS() {
Set<Node> visited = new HashSet<>();
List<Edge> path = new ArrayList<>();
Map<Node, Edge> edgeTowardsHere = new HashMap<>();
Deque<Node> q = new LinkedList<>();
q.add(source);
while (!q.isEmpty()) {
Node u = q.remove();
visited.add(u);
if (u == sink)
break;
for (Edge e : u.edges) {
Node v = e.to;
int bottleneck = e.cap - e.flow;
if (visited.contains(v) || bottleneck <= 0)
continue;
q.add(v);
edgeTowardsHere.put(v, e);
}
}
if (!visited.contains(sink))
return null;
// find the actual path to here
Node current = sink;
while (current != source) {
Edge e = edgeTowardsHere.get(current);
path.add(e);
current = e.from;
}
return path;
}
}