Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.FileReader;
- import java.io.FileWriter;
- import java.io.PrintWriter;
- import java.util.ArrayList;
- import java.util.HashSet;
- import java.util.StringTokenizer;
- public class grass {
- /*
- * grass cownoisseur
- */
- /*
- * algo:
- * first find all SCCs
- * then toposort
- * then DFS down and count cows longest paths. If current node in dfs has parent that is ancestor of node containing barn, then we DFS that node too and eliminate the up arrow
- */
- static final int infinity = -1000000;
- static boolean[] visited;
- static int[] id;
- static int[] lowlink;
- static int pre;
- static int count = 0;
- static ArrayList<Integer> stack;
- public static void tarjan(Vertex[] vertices) {
- visited = new boolean[vertices.length];
- stack = new ArrayList<Integer>();
- id = new int[vertices.length];
- lowlink = new int[vertices.length];
- for (int v = 0; v < vertices.length; v++) {
- if (!visited[v]) tarjandfs(vertices, v);
- }
- }
- public static void tarjandfs(Vertex[] vertices, int v) {
- visited[v] = true;
- lowlink[v] = pre++;
- int min = lowlink[v];
- stack.add(v);
- for (Vertex w : vertices[v].adjacents) {
- if (!visited[w.number]) tarjandfs(vertices, w.number);
- if (lowlink[w.number] < min) min = lowlink[w.number];
- }
- if (min < lowlink[v]) {
- lowlink[v] = min;
- return;
- }
- int w;
- do {
- w = stack.remove(stack.size() - 1);
- id[w] = count;
- lowlink[w] = vertices.length;
- } while (w != v);
- count++;
- }
- public static void main(String[] args) throws Exception {
- //BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
- //PrintWriter w = new PrintWriter(System.out);
- BufferedReader r = new BufferedReader(new FileReader("grass.in"));
- PrintWriter w = new PrintWriter(new BufferedWriter(new FileWriter("grass.out")));
- StringTokenizer st = new StringTokenizer(r.readLine());
- int n = Integer.parseInt(st.nextToken());
- int m = Integer.parseInt(st.nextToken());
- Vertex[] initialGraph = new Vertex[n];
- for (int i = 0; i < initialGraph.length; i++) {
- initialGraph[i] = new Vertex(i);
- }
- for (int i = 0; i < m; i++) {
- st = new StringTokenizer(r.readLine());
- int a = Integer.parseInt(st.nextToken()) - 1;
- int b = Integer.parseInt(st.nextToken()) - 1;
- initialGraph[a].addPath(initialGraph[b], 1);
- }
- //run tarjan
- tarjan(initialGraph);
- int[] components = new int[count];
- for (int i = 0; i < id.length; i++) {
- components[id[i]]++;
- }
- int uniquescc = count;
- Vertex[] vertices = new Vertex[uniquescc];
- for (int i = 0; i <vertices.length; i++) {
- vertices[i] = new Vertex(i);
- vertices[i].pastureCount = components[i];
- }
- Vertex barn = vertices[id[0]];
- for (int i = 0; i < initialGraph.length; i++) {
- for (int j = 0; j < initialGraph[i].adjacents.size(); j++) {
- //If i is not in the same connected component as neighbor j
- int icomponent = id[i];
- int jcomponent = id[initialGraph[i].adjacents.get(j).number];
- if (icomponent != jcomponent) {
- //add the path
- //if we haven't already added the path
- if (!vertices[icomponent].alreadyAdded.contains(vertices[jcomponent])) {
- vertices[icomponent].addPath(vertices[jcomponent], vertices[jcomponent].pastureCount);
- vertices[jcomponent].addParent(vertices[icomponent], vertices[icomponent].pastureCount); //reverse edge
- }
- }
- }
- }
- //DFS on parents
- barn.barnancestor = true;
- barn.distance = 0;
- ancestordfs(barn);
- //Find longest paths to all children
- ArrayList<Integer> ordered = new ArrayList<Integer>();
- for (int i = count - 1; i >= 0; i--) {
- ordered.add(i);
- }
- dpdown(vertices, ordered);
- dpup(vertices, ordered);
- int answer = barn.pastureCount;
- for (int i = 0; i < vertices.length; i++) {
- if (!vertices[i].barnancestor) {
- for (int j = 0; j < vertices[i].parents.size(); j++) {
- if (vertices[i].parents.get(j).barnancestor) {
- answer = Math.max(answer, vertices[i].distance + vertices[i].parents.get(j).distance + barn.pastureCount);
- }
- }
- }
- }
- barn.barnancestor = false;
- for (int i = 0; i < vertices.length; i++) {
- if (!vertices[i].barnancestor) {
- for (int j = 0; j < vertices[i].parents.size(); j++) {
- if (vertices[i].parents.get(j).barnancestor) {
- answer = Math.max(answer, vertices[i].distance + vertices[i].parents.get(j).distance + barn.pastureCount);
- }
- }
- }
- }
- w.println(answer);
- w.flush();
- }
- public static void dpdown(Vertex[] vertices, ArrayList<Integer> order) {
- for (int i = 0; i < order.size(); i++) {
- Vertex current = vertices[order.get(i)];
- if (current.barnancestor && current != vertices[id[0]]) continue;
- for (int j = 0; j < current.adjacents.size(); j++) {
- current.adjacents.get(j).distance = Math.max(current.adjacents.get(j).distance, current.distance + current.costs.get(j));
- }
- }
- }
- public static void dpup(Vertex[] vertices, ArrayList<Integer> order) {
- for (int i = order.size() - 1; i >= 0; i--) {
- Vertex current = vertices[order.get(i)];
- if (!current.barnancestor) continue;
- for (int j = 0; j < current.parents.size(); j++) {
- current.parents.get(j).distance = Math.max(current.parents.get(j).distance, current.distance + current.parentCosts.get(j));
- }
- }
- }
- public static void ancestordfs(Vertex current) {
- for (int i = 0; i < current.parents.size(); i++) {
- Vertex parent = current.parents.get(i);
- if (!parent.barnancestor) {
- parent.barnancestor = true;
- ancestordfs(parent);
- }
- }
- }
- public static class Vertex implements Comparable<Vertex> {
- int number;
- ArrayList<Vertex> adjacents = new ArrayList<Vertex>();
- ArrayList<Integer> costs = new ArrayList<Integer>();
- ArrayList<Vertex> parents = new ArrayList<Vertex>();
- ArrayList<Integer> parentCosts = new ArrayList<Integer>();
- HashSet<Vertex> alreadyAdded = new HashSet<Vertex>();
- int distance = infinity;
- boolean intree = false;
- int to = 0;
- Vertex previous;
- boolean visited = false;
- boolean inQueue = false;
- int flow = infinity;
- int pastureCount;
- boolean barnancestor = false;
- public Vertex(int n) {
- number = n;
- }
- public void addPath(Vertex to, int value) {
- adjacents.add(to);
- costs.add(value);
- alreadyAdded.add(to);
- }
- public void addParent(Vertex p, int value) {
- parents.add(p);
- parentCosts.add(value);
- alreadyAdded.add(p);
- }
- public String toString() {
- return number + " " + distance;
- }
- public int compareTo(Vertex v) {
- return adjacents.size() - v.adjacents.size();
- }
- public int hashCode() {
- return number;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement