Cod sursa(job #2694544)

Utilizator clupauCatalin Lupau clupau Data 9 ianuarie 2021 17:33:28
Problema Critice Scor 20
Compilator java Status done
Runda Arhiva de probleme Marime 5.16 kb
//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;
    }
}