From fc5aee56466e11079b1662c7d500a8662775331c Mon Sep 17 00:00:00 2001 From: Diogo Cordeiro Date: Wed, 3 Feb 2021 23:38:26 +0000 Subject: [PATCH] Add code --- Couple.java | 83 +++++++++ DFS.java | 129 ++++++++++++++ DirectedMultiGraph.java | 85 ++++++++++ DirectedWeightedGraph.java | 275 ++++++++++++++++++++++++++++++ FastPrint.java | 10 ++ FastScanner.java | 61 +++++++ FloydWarshall.java | 90 ++++++++++ InsertSort.java | 26 +++ Johnson.java | 34 ++++ LIS.java | 91 ++++++++++ README.md | 32 +++- SegmentTree.java | 318 +++++++++++++++++++++++++++++++++++ ValueThenKeyComparator.java | 17 ++ bfs_scc.java | 22 +++ bfs_shortest_path.java | 54 ++++++ collections_count_if.java | 56 ++++++ knapsack.java | 65 +++++++ minimum_gap_schedulling.java | 85 ++++++++++ 18 files changed, 1532 insertions(+), 1 deletion(-) create mode 100644 Couple.java create mode 100644 DFS.java create mode 100644 DirectedMultiGraph.java create mode 100644 DirectedWeightedGraph.java create mode 100644 FastPrint.java create mode 100644 FastScanner.java create mode 100644 FloydWarshall.java create mode 100644 InsertSort.java create mode 100644 Johnson.java create mode 100644 LIS.java create mode 100644 SegmentTree.java create mode 100644 ValueThenKeyComparator.java create mode 100644 bfs_scc.java create mode 100644 bfs_shortest_path.java create mode 100644 collections_count_if.java create mode 100644 knapsack.java create mode 100644 minimum_gap_schedulling.java diff --git a/Couple.java b/Couple.java new file mode 100644 index 0000000..f0d8ee3 --- /dev/null +++ b/Couple.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Objects; + +/** + * Container to ease passing around a tuple of two objects. This object provides a sensible + * implementation of equals(), returning true if equals() is true on each of the contained + * objects. + * + * @link https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util/Pair.java + */ +public class Couple { + public final F first; + public final S second; + + /** + * Constructor for a Couple. + * + * @param first the first object in the Couple + * @param second the second object in the Couple + */ + public Couple(F first, S second) { + this.first = first; + this.second = second; + } + + /** + * Checks the two objects for equality by delegating to their respective + * {@link Object#equals(Object)} methods. + * + * @param o the {@link Couple} to which this one is to be checked for equality + * @return true if the underlying objects of the Couple are both considered + * equal + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Couple)) { + return false; + } + Couple p = (Couple) o; + return Objects.equals(p.first, first) && Objects.equals(p.second, second); + } + + /** + * Compute a hash code using the hash codes of the underlying objects + * + * @return a hashcode of the Couple + */ + @Override + public int hashCode() { + return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); + } + + @Override + public String toString() { + return "Couple{" + String.valueOf(first) + " " + String.valueOf(second) + "}"; + } + + /** + * Convenience method for creating an appropriately typed couple. + * + * @param a the first object in the Couple + * @param b the second object in the Couple + * @return a Couple that is templatized with the types of a and b + */ + public static Couple create(A a, B b) { + return new Couple(a, b); + } +} diff --git a/DFS.java b/DFS.java new file mode 100644 index 0000000..1623f6a --- /dev/null +++ b/DFS.java @@ -0,0 +1,129 @@ +package CompetitiveProgramming.Uva; + +import CompetitiveProgramming.DirectedMultiGraph; + +import java.util.*; + +public class +M11709 +{ + static DirectedMultiGraph g, g_transpose; + static int n_nodes, // P + T, + idx; + static Map name_idx; + private static int number_of_scc = 0, + current_scc_n_nodes = 0; + + /** + * WARNING: Changes all graph nodes' visited state to true + * temporary storage: current_scc_n_nodes won't be reset by the end + * + * Time complexity: O(E+N) + * void operations: Will set number_of_scc + * + * @param g DirectedMultiGraph The graph to be used + * @param u int The start point + * @param dfs_finished_stack Stack ending_sequence I/O (optional) If DAG is given, + * it will correspond to a top sort (total order) + */ + @SafeVarargs + private static void + dfs_visit(DirectedMultiGraph g, int u, ArrayDeque... dfs_finished_stack) { + g.seen[u] = true; + ++current_scc_n_nodes; + + for (int w : g.edges(u)) { + if (!g.seen[w]) { + dfs_visit(g, w, dfs_finished_stack); + } + } + + // Check if a dfs_finished_stack was supplied to be filled + if (dfs_finished_stack.length == 1) { + dfs_finished_stack[0].addFirst(u); + } + } + + // Time complexity: O(E+N) + private static void + kosaraju_sharir(DirectedMultiGraph g, DirectedMultiGraph g_transpose, int n_nodes) { + // DFS visit the graph + ArrayDeque dfs_finished_stack = new ArrayDeque<>(); + for (int v = 0; v < n_nodes; ++v) { + if (!g.seen[v]) { + dfs_visit(g, v, dfs_finished_stack); + } + } + + // Reset globals + current_scc_n_nodes = 0; + number_of_scc = 0; + + // DFS visit in transposed graph using dfs_finished_stack seq + while (!dfs_finished_stack.isEmpty()) { + int v = dfs_finished_stack.removeFirst(); + + // New component is being discovered + if (!g_transpose.seen[v]) { + current_scc_n_nodes = 0; + dfs_visit(g_transpose, v); + + // Actions + ++number_of_scc; + } + } + } + + public static int + idx_in_graph(String name) { + Integer u = name_idx.get(name); + if (u == null) { + u = idx++; + name_idx.put(name, u); + } + return u; + } + + public static boolean + generate_structures(Scanner stdin) { + if (n_nodes == 0 && T == 0) return false; + stdin.nextLine(); // flush from int buffer + name_idx = new HashMap<>(n_nodes); + idx = 0; + g = new DirectedMultiGraph(n_nodes, true); + g_transpose = new DirectedMultiGraph(n_nodes, true); + + for (int p = 0; p < n_nodes; ++p) { + String name = stdin.nextLine(); + idx_in_graph(name); + } + for (int t = 0; t < T; ++t) { + String u_name = stdin.nextLine(), + w_name = stdin.nextLine(); + int u = idx_in_graph(u_name), + w = idx_in_graph(w_name); + g.link_first(u, w); + g_transpose.link_first(w, u); + } + + return true; + } + + public static void + main(String[] args) { + // Input and Data Representation + Scanner stdin = new Scanner(System.in); + while (true) { + n_nodes = stdin.nextInt(); + T = stdin.nextInt(); + if (!generate_structures(stdin)) break; + // Process + kosaraju_sharir(g, g_transpose, n_nodes); + // Output + System.out.println(number_of_scc); + } + // That's all folks + stdin.close(); + } +} diff --git a/DirectedMultiGraph.java b/DirectedMultiGraph.java new file mode 100644 index 0000000..8ab016b --- /dev/null +++ b/DirectedMultiGraph.java @@ -0,0 +1,85 @@ +import java.util.*; + +/** + * The DirectedMultiGraph class is a structure to store a non-weighted + * graph of nodes named 0 through N-1. + * The implementation uses an adjacency-lists representation. + * @author Diogo Peralta Cordeiro + */ +public class +DirectedMultiGraph +{ + private final List> edges; + public final int[] out_degree, in_degree; + public int n_nodes, n_edges; // N, #Edges, respectively + + // O(n) to construct the structure + public + DirectedMultiGraph (int n_nodes) + { + this.n_nodes = n_nodes; + this.n_edges = 0; + this.edges = new ArrayList<>(n_nodes); + this.out_degree = new int[n_nodes]; + this.in_degree = new int[n_nodes]; + for (int i = 0; i < n_nodes; ++i) + { + this.edges.add(i, new LinkedList<>()); + } + } + + // O(1) to get the adjacency-list for a node + public LinkedList + edges (int u) + { + return this.edges.get(u); + } + + // O(1) to get the first adjacency of a node + public int + first_edge (int u) + { + return this.edges.get(u).getFirst(); + } + + // O(1) to add an adjacency + public final void + link_first (int u, int w) + { + // If we don't want a Multi-graph and can't avoid + // duplicate links from the outside, uncomment the following + // line + //if (node_links(u).contains(w)) return; + this.edges(u).addFirst(w); + ++this.out_degree[u]; + ++this.in_degree[w]; + ++this.n_edges; + } + + // O(1) to remove an adjacency + public void + unlink_first (int u) + { + try + { + int w = this.edges(u).removeFirst(); + --this.out_degree[u]; + --this.in_degree[w]; + --this.n_edges; + } + catch (NoSuchElementException e) + { + // void. + } + } + + // Convenience: In case the requester needs to hold such type of information about the nodes + public boolean[] seen; + public + DirectedMultiGraph (int n_nodes, boolean have_seen) + { + this(n_nodes); + if (have_seen) + seen = new boolean[n_nodes]; + } +} diff --git a/DirectedWeightedGraph.java b/DirectedWeightedGraph.java new file mode 100644 index 0000000..f9176f0 --- /dev/null +++ b/DirectedWeightedGraph.java @@ -0,0 +1,275 @@ +import java.util.*; + +/** + * The DirectedWeightedGraph class is a structure to store a n-weighted + * graph of nodes named 0 through N-1. + * The implementation uses an adjacency-lists representation for the graph + * and a HashMap indexed by strings of the form "u-v", u and v being nodes, + * the map's values are a List of generic type. + * Each edge can have a different number of weights (or even none). + * @author Diogo Peralta Cordeiro + */ +public class +DirectedWeightedGraph +{ + private final List> edges; + private final Map> edges_weights; + public int n_nodes, n_edges; // N, #Edges, respectively + + // O(n) to construct the structure + public + DirectedWeightedGraph (int n_nodes) + { + this.n_nodes = n_nodes; + this.n_edges = 0; + this.edges = new ArrayList<>(n_nodes); + this.edges_weights = new HashMap<>(n_nodes); + for (int i = 0; i < n_nodes; ++i) + { + this.edges.add(i, new LinkedList<>()); + } + } + + // O(1) to get the adjacency-list for a node + public LinkedList + edges (int u) + { + return this.edges.get(u); + } + + // O(1) to get the weights list + public List + weight (int u, int w) + { + return this.edges_weights.get(u + "-" + w); + } + + // O(1) to add a node to the last position of the adjacency-list + // O(1) to update the weight of an existing edge + @SafeVarargs + public final void + link (int u, int w, T... weight) + { + // O(1) to ensure we don't make a MultiGraph + if (!this.edges(u).contains(w)) { + // O(1) to add an adjacency + this.edges(u).addLast(w); + + ++this.n_edges; + } + + // O(1) to put or update a weight, if we want to + this.edges_weights.put(u + "-" + w, Arrays.asList(weight)); + } + + // O(n) to remove a node + public void + delete_node (int u) + { + for (int w = 0; w < this.n_nodes; ++w) + { + this.unlink(u, w); + this.unlink(w, u); + } + } + + // O(n) to remove an adjacency + public void + unlink (int u, int w) + { + // O(n) + this.edges(u).remove((Integer) w); + + // O(1) + this.edges_weights.remove(u + "-" + w); + + --this.n_edges; + } + + /* UTILS */ + + // O(#Edges + N*lg(N)) + public List + int_dijkstra(int s) { + /* Set Data Structures */ + int[] dist = new int[this.n_nodes]; + List> come_from = new ArrayList<>(this.n_nodes); + for (int i = 0; i < this.n_nodes; ++i) { + dist[i] = 1000000000; // 1e9 to avoid overflow + come_from.add(i, new LinkedList<>()); + } + // Compare by distance, then by index + TreeSet to_explore = new TreeSet<>(Comparator.comparingInt((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + dist[s] = 0; + to_explore.add(s); + + // Dijkstra's Algorithm + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + // Assert: u.distance is the true shortest distance from s to u + // Assert: u is never put back into to_explore + this.edges(u).forEach((w) -> { + int edge_cost = (int) this.weight(u, w).get(0); + int dist_w = dist[u] + edge_cost; + if (dist_w < dist[w]) { + come_from.get(w).clear(); + come_from.get(w).add(u); + // Decrease key with new distance + to_explore.remove(w); + dist[w] = dist_w; + to_explore.add(w); + } else if (dist_w == dist[w]) { + come_from.get(w).add(u); + } + }); + } + + // That's all folks. + return Arrays.asList(dist, come_from); + } + public List + double_dijkstra(int s) { + /* Set Data Structures */ + double[] dist = new double[this.n_nodes]; + List> come_from = new ArrayList<>(this.n_nodes); + for (int i = 0; i < this.n_nodes; ++i) { + dist[i] = 1000000000; // 1e9 to avoid overflow + come_from.add(i, new LinkedList<>()); + } + // Compare by distance, then by index + TreeSet to_explore = new TreeSet<>(Comparator.comparingDouble((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + dist[s] = 0; + to_explore.add(s); + + // Dijkstra's Algorithm + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + // Assert: u.distance is the true shortest distance from s to u + // Assert: u is never put back into to_explore + this.edges(u).forEach((w) -> { + double edge_cost = (double) this.weight(u, w).get(0); + double dist_w = dist[u] + edge_cost; + if (Double.compare(dist_w, dist[w]) < 0) { + come_from.get(w).clear(); + come_from.get(w).add(u); + // Decrease key with new distance + to_explore.remove(w); + dist[w] = dist_w; + to_explore.add(w); + } else if (Double.compare(dist_w, dist[w]) == 0) { + come_from.get(w).add(u); + } + }); + } + + // That's all folks. + return Arrays.asList(dist, come_from); + } + + // O(#Edges + N*lg(N)) + public int[] + int_prim() { + /* Set Data Structures */ + int[] dist = new int[this.n_nodes]; + boolean[] in_tree = new boolean[this.n_nodes]; + int[] come_from = new int[this.n_nodes]; + Arrays.fill(dist, 1000000000); // 1e9 to avoid overflow + TreeSet to_explore = new TreeSet<>(Comparator.comparingInt((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + int s = 0; + dist[s] = 0; + to_explore.add(s); + + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + in_tree[u] = true; + // Let t be the graph made of nodes with in_tree = true, + // and edges {(w - come_from[w]), for w in g.nodes excluding s} + // Assert: t is part of an MST for g + this.edges(u).forEach((w) -> { + int edge_cost = (int) this.weight(u, w).get(0); + if (!in_tree[w] && edge_cost < dist[w]) { + come_from[w] = u; + to_explore.remove(w); + dist[w] = edge_cost; + to_explore.add(w); + } + }); + } + + // That's all folks. + return come_from; + } + public int[] + double_prim() { + /* Set Data Structures */ + double[] dist = new double[this.n_nodes]; + boolean[] in_tree = new boolean[this.n_nodes]; + int[] come_from = new int[this.n_nodes]; + Arrays.fill(dist, 1000000000); // 1e9 to avoid overflow + TreeSet to_explore = new TreeSet<>(Comparator.comparingDouble((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + int s = 0; + dist[s] = 0; + to_explore.add(s); + + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + in_tree[u] = true; + // Let t be the graph made of nodes with in_tree = true, + // and edges {(w - come_from[w]), for w in g.nodes excluding s} + // Assert: t is part of an MST for g + this.edges(u).forEach((w) -> { + double edge_cost = (double) this.weight(u, w).get(0); + if (!in_tree[w] && Double.compare(edge_cost, dist[w]) < 0) { + come_from[w] = u; + to_explore.remove(w); + dist[w] = edge_cost; + to_explore.add(w); + } + }); + } + + // That's all folks. + return come_from; + } + + // O(N*#Edges) + public int[] + int_bellman_ford (int s) throws Exception { + int[] min_weight = new int[this.n_nodes]; + // best estimate so far of minimum weight from s to another vertex + Arrays.fill(min_weight, 1000000000); // 1e9 to avoid overflow + min_weight[s] = 0; + + // Repeat + for (int i = 0; i < this.n_nodes; ++i) { + // relax all the edges + for (int u = 0; u < this.n_nodes; ++u) { + for (int w : this.edges(u)) { + int edge_cost = (int) this.weight(u, w).get(0); + min_weight[w] = Math.min(min_weight[u] + edge_cost, min_weight[w]); + // Assert: v.min_weight >= true minimum weight from s to v + } + } + } + + for (int u = 0; u < this.n_nodes; ++u) { + for (int w : this.edges(u)) { + int edge_cost = (int) this.weight(u, w).get(0); + if (min_weight[u] + edge_cost < min_weight[w]) { + throw new Exception("Negative-weight cycle detected."); + } + } + } + + // That's all folks. + return min_weight; + } +} diff --git a/FastPrint.java b/FastPrint.java new file mode 100644 index 0000000..9f01ea4 --- /dev/null +++ b/FastPrint.java @@ -0,0 +1,10 @@ +package ProgrammingChallenges; +// FastPrint (remember to call FastPrint.out.close() at the end) +// Pedro Ribeiro (DCC/FCUP) + +import java.io.BufferedOutputStream; +import java.io.PrintWriter; + +public class FastPrint { + public static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out)); +} diff --git a/FastScanner.java b/FastScanner.java new file mode 100644 index 0000000..ef3c7a8 --- /dev/null +++ b/FastScanner.java @@ -0,0 +1,61 @@ +package ProgrammingChallenges; +// FastScanner +// Pedro Ribeiro (DCC/FCUP) +// Minor edits by Diogo Cordeiro + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.StringTokenizer; + +public class FastScanner { + BufferedReader br; + StringTokenizer st; + + public FastScanner(InputStream stream) { + br = new BufferedReader(new InputStreamReader(stream)); + } + + public String next() { + while (st == null || !st.hasMoreElements()) { + String ffs = null; + try { + ffs = br.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + if (ffs != null) + st = new StringTokenizer(ffs); + else return null; + } + return st.nextToken(); + } + + //public Integer nextInt() { + public int nextInt() { + //String n = next(); + //if (n == null) return null; + //return Integer.parseInt(n); + return Integer.parseInt(next()); + } + + public long nextLong() { + return Long.parseLong(next()); + } + + public double nextDouble() { + return Double.parseDouble(next()); + } + + public String nextLine() { + String str = ""; + try { + str = br.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + return str; + } + +} diff --git a/FloydWarshall.java b/FloydWarshall.java new file mode 100644 index 0000000..e95d283 --- /dev/null +++ b/FloydWarshall.java @@ -0,0 +1,90 @@ +/* Input */ +// Information about the group +int n_elements = stdin.nextInt(), + start = stdin.nextInt(), + budget = stdin.nextInt(), +// Information about the network + n_nodes = stdin.nextInt(), + n_edges = stdin.nextInt(), + NO_EDGE = 1000000000; // 1e9 to avoid overflow +// Graph as a adjacency-matrix +int[][] adj = new int[n_nodes][n_nodes]; +for (int i = 0; i < n_nodes; ++i) +{ + Arrays.fill(adj[i], NO_EDGE); + adj[i][i] = 0; +} +for (int i = 0; i < n_edges; ++i) +{ + int source = stdin.nextInt()-1, + dest = stdin.nextInt()-1, + spots = stdin.nextInt(), + cost = stdin.nextInt(); + + if (spots >= n_elements + && cost <= budget) // prevents stupidly expensive edges + { + adj[source][dest] = cost; + } + else + { + adj[source][dest] = NO_EDGE; + } +} + +// Let's keep a fast access to the path +int[][] path = new int[n_nodes][n_nodes]; +for (int i = 0; i < n_nodes; ++i) +{ + for (int j = 0; j < n_nodes; ++j) + { + if (adj[i][j] == NO_EDGE) + { + path[i][j] = -1; + } + else + { + path[i][j] = i; + } + } +} + +/* Floyd-Warshall */ +for (int k = 0; k < n_nodes; ++k) +{ + for (int i = 0; i < n_nodes; ++i) + { + for (int j = 0; j < n_nodes; ++j) + { + if (adj[i][j] > adj[i][k] + adj[k][j]) + { + adj[i][j] = adj[i][k] + adj[k][j]; + path[i][j] = path[k][j]; + } + } + } +} + +// Path from a given `start` to every other node in the graph +ArrayDeque indexes = new ArrayDeque<>(); +next_route: +for (int end = 0; end < n_nodes; ++end) +{ + indexes.clear(); + indexes.addFirst(end); + + int current_end = end, + previous; + while (path[start][current_end] != start) + { + previous = path[start][current_end]; + if (previous == -1) // No possible path + { + continue next_route; + } + indexes.addFirst(previous); + current_end = previous; + } + indexes.addFirst(start); + System.out.println("Get to node " + end + " costs " + adj[start][end] + "."); +} diff --git a/InsertSort.java b/InsertSort.java new file mode 100644 index 0000000..c70f618 --- /dev/null +++ b/InsertSort.java @@ -0,0 +1,26 @@ +import java.util.Arrays; + +public class insertsort +{ + public static void main (String[] args) + { + int[] in = {5,1,2,3}; + + System.out.println("Before insertion sort: " + Arrays.toString(in)); + + for (int i = 1; i < in.length; ++i) + { + int j = i - 1; // Ensure we don't get in a off by one error + while (j >= 0 && in[j] > in[j + 1]) + { + int t = in[j]; + in[j] = in[j+1]; + in[j+1] = t; + --j; // Ensure that all the positions before are still correct + } + } + + System.out.println("After insertion sort: " + Arrays.toString(in)); + } +} + diff --git a/Johnson.java b/Johnson.java new file mode 100644 index 0000000..9219c82 --- /dev/null +++ b/Johnson.java @@ -0,0 +1,34 @@ +// You have a graph G (original graph), with edge weight values v(u->w) +// You must call this function with a helper graph with a special node +// indexed 0 and zero-weight edges 0->w for all vertices w +// Time complexity: O(N^2 * lg N + N*#Edges) +// Returns APSP indexed as expected in the original graph (i.e., +// shifting everything -1 to exclude the special node of the helper graph) +private static int[][] +int_johnson (DirectedWeightedGraph hg) throws Exception +{ + // Finish the helper graph by running Bellman-Ford on it + int[] h = hg.int_bellman_ford(0); + + // Generate the tweaked graph + for (int u = 1; u < hg.n_nodes; ++u) { + hg.edges(u).forEach((w) -> { + int edge_cost = (int) hg.weight(u, w).get(0); + // Update edge's cost + hg.link(u, w, edge_cost + h[u] - h[w]); + } + } + + int [][] D = new int[hg.n_nodes-1][hg.n_nodes-1]; + + // Dijkstra on the tweaked graph + for (int u = 0; u < g.n_nodes-1; ++u) { + for (int w = 0; w < g.n_nodes-1; ++w) { + int[] delta = hg.int_dijkstra(u+1); + D[u][w] = delta[w+1] + h[w+1] - h[u+1]; + } + } + + // Johnson drops mic. + return D; +} diff --git a/LIS.java b/LIS.java new file mode 100644 index 0000000..314944f --- /dev/null +++ b/LIS.java @@ -0,0 +1,91 @@ +package ProgrammingChallenges.Uva; + +import ProgrammingChallenges.FastPrint; + +import java.io.BufferedOutputStream; +import java.io.PrintWriter; +import java.util.Scanner; +import java.util.stream.IntStream; + +public class +UVA10534 { + // https://stackoverflow.com/a/17660641 + // Time complexity: O(n*lg(n)) + public static int[] + LIS(int[] a) { + int n = a.length; + int INF = 1000000000; + int[] seq = new int[n]; + int[] d = new int[n + 1]; + d[0] = -INF; + for (int i = 1; i < n + 1; ++i) { + seq[i - 1] = 1; + d[i] = INF; + } + + for (int i = 1; i < n + 1; ++i) { + int low = 0, + high = i; + while (low <= high) { + int mid = low + (high - low) / 2; + if (d[mid] < a[i - 1]) { + low = mid + 1; + } else { + high = mid - 1; + } + } + d[low] = a[i - 1]; + seq[i - 1] = low; + } + + return seq; + } + + public static int[] + reverse_arr(int[] seq) { + /*int[] reverse_seq = new int[seq.length]; + for (int i = 0, j = seq.length-1; i < seq.length; ++i, --j) + reverse_seq[j] = seq[i];*/ + return IntStream.range(0, seq.length) + .map(i -> seq[seq.length - 1 - i]) + .toArray(); + } + + public static int[] + LDS(int[] seq) { + /*int[] reverse_seq = IntStream.range(0, seq.length) + .map(i -> seq[seq.length - 1 - i]) + .toArray();*/ + /*int[] reverse_seq = new int[seq.length]; + for (int i = 0, j = seq.length-1; i < seq.length; ++i, --j) + reverse_seq[j] = seq[i];*/ + return reverse_arr(LIS(reverse_arr(seq))); + } + + public static void + main(String[] args) { + Scanner stdin = new Scanner(System.in); + while (stdin.hasNext()) { + // Input + int N = stdin.nextInt(); + int[] seq = new int[N]; + for (int i = 0; i < N; ++i) { + seq[i] = stdin.nextInt(); + } + //System.out.println(Arrays.toString(seq)); + + // Process + int[] lis = LIS(seq); + int[] lds = LDS(seq); + int ans = 0; + for (int i = 0; i < N; ++i) { + //System.out.println(lis[i] + " " + lds[i]); + int min = Math.min(lis[i], lds[i]); + ans = Math.max(ans, 2 * min - 1); + } + // Output + FastPrint.out.println(ans); + } + FastPrint.out.close(); + } +} diff --git a/README.md b/README.md index 6634d0c..7a0d661 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,33 @@ # JavaAlgorithms -These are some Java code I wrote throughout my first degree in CompSci. +These are some Java code I wrote throughout my first degree in Computer Science. There is some third party code properly credited and with its associated license. + +## Files Descriptions + +### Code I wrote +* [Directed MultiGraph](DirectedMultiGraph.java) - Adjacency-list non-weighted directed multi-graphs (data structure) +* [Directed Weighted Graph](DirectedWeightedGraph.java) - Adjacency-list n-weighted directed graphs (data structure) +* [Dijkstra](DirectedWeightedGraph.java#L91) - Adjacency-list Dijkstra's algorithm implementation (SSC non-negative weights only) +* [Prim](DirectedWeightedGraph.java#L173) - Adjacency-list Prim's algorithm implementation (MST) +* [Bellman-Ford](DirectedWeightedGraph.java#L243) - Adjacency-list Bellman-ford (SSC) +* [Floyd Warshall](FloydWarshall.java) - Adjacency-matrix Floyd Warshall (APSP) +* [Johnson](Johnson.java) - Johnson's Algorithm (sparse graph APSP) +* [Insert Sort](InsertSort.java) - An Insertion Sort implementation (sorting) +* [DFS and Topological Sorting](DFS.java#L18) - Adjacency-list DFS with TopSort implementation (graph traversal and sorting) +* [Kosaraju-Sharir](DFS.java#L48) - Adjacency-list Kosaraju-Sharir implementation (SCC) +* [BFS non-directed SCC](bfs_scc.java) - Adjacency-list BFS implementation to identify SCC in a non-directed graph (graph traversal and SCC non-directed only) +* [BFS non-weighted SSC](bfs_shortest_path.java) - Adjacency-list BFS for shortest path in a non-weighted graph (SSC non-weighted) +* [LIS](LIS.java) - A Longest Increasing Sequence algorithm implmentation (substring) +* [Collections Count If](collections_count_if.java#L46) - Counts elements for which predicate p returns true (collection utility) + + +### Third party code +* [Couple](Couple.java) - A AOSP class to handle 2-tuples +* [Segment Tree](SegmentTree.java) - A Segment Tree data structure implementation derived from Segewick and Wayne's Algorithms, 4th ed. book +* [ValueThenKeyComparator](ValueThenKeyComparator.java) - A Comparator that sorts Map.Entry objects with Comparable keys and values, first by value, then by key +* [FastScanner](FastScanner.java) - Fast Input from STDIN in Java +* [FastPrint](FastPrint.java) - Fast Output from STDOUT in Java + +### Example code +* [Activity Minimum Gap Schedulling](minimum_gap_schedulling.java) - Activity Minimum Gap Schedulling implementation (sorting) +* [Knapsack](knapsack.java) - Knapsack approximation solution using conditional binary search (search and optimization) diff --git a/SegmentTree.java b/SegmentTree.java new file mode 100644 index 0000000..6e895bc --- /dev/null +++ b/SegmentTree.java @@ -0,0 +1,318 @@ +/****************************************************************************** + * + * A segment tree data structure. + * + ******************************************************************************/ + +import java.util.Arrays; + +/** + * The {@code SegmentTree} class is a structure for efficient search of cumulative data. + * It performs Range Min, Max, Sum and Multiplication Queries in O(log(n)) time. + *

+ * Also it has been develop with {@code LazyPropagation} for range updates, which means + * when you perform update operations over a range, the update process affects the least nodes as possible + * so that the bigger the range you want to update the less time it consumes to update it. Eventually those changes will be propagated + * to the children and the whole array will be up to date. + *

+ * Example: + *

+ * SegmentTreeHeap st = new SegmentTreeHeap(new Integer[]{1,3,4,2,1, -2, 4}); + * st.update(0,3, 1) + * In the above case only the node that represents the range [0,3] will be updated (and not their children) so in this case + * the update task will be less than n*log(n) + *

+ * Memory usage: O(n) + * + * @author Ricardo Pacheco (base code) + * @author Diogo Cordeiro (implemented range max and multiplication queries, plus other minor changes) + * @link https://algs4.cs.princeton.edu/99misc/SegmentTree.java.html + */ +public class SegmentTree { + + private final STNode[] heap; + private final int[] array; + + /** + * Time-Complexity: O(n*log(n)) + * + * @param array the Initialization array + */ + public SegmentTree(int[] array) { + this.array = Arrays.copyOf(array, array.length); + // The max size of this array is about 2 * 2 ^ log2(n) + 1 + int size = (int) (2 * Math.pow(2.0, Math.floor((Math.log(array.length) / Math.log(2.0)) + 1))); + heap = new STNode[size]; + build(1, 0, array.length); + } + + public int size() { + return array.length; + } + + // Initialize the Nodes of the Segment tree + private void build(int v, int from, int size) { + heap[v] = new STNode(); + heap[v].from = from; + heap[v].to = from + size - 1; + + if (size == 1) { + heap[v].sum = array[from]; + heap[v].mul = array[from]; + heap[v].min = array[from]; + heap[v].max = array[from]; + } else { + // Build childs + build(2 * v, from, size / 2); + build(2 * v + 1, from + size / 2, size - size / 2); + + heap[v].sum = heap[2 * v].sum + heap[2 * v + 1].sum; + heap[v].mul = heap[2 * v].mul * heap[2 * v + 1].mul; + // min = min of the children + heap[v].min = Math.min(heap[2 * v].min, heap[2 * v + 1].min); + // max = max of the children + heap[v].max = Math.max(heap[2 * v].max, heap[2 * v + 1].max); + } + } + + /** + * Range Sum Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @return sum + */ + public int rsq(int from, int to) { + return rsq(1, from, to); + } + + private int rsq(int v, int from, int to) { + STNode n = heap[v]; + + // If you did a range update that contained this node, you can infer the Sum without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) { + return (to - from + 1) * n.pendingVal; + } + + if (contains(from, to, n.from, n.to)) { + return heap[v].sum; + } + + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftSum = rsq(2 * v, from, to); + int rightSum = rsq(2 * v + 1, from, to); + + return leftSum + rightSum; + } + + return 0; + } + + /** + * Range Multiplication Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @author Diogo Peralta Cordeiro + * @return multiplication + */ + public int rmq(int from, int to) { + return rmq(1, from, to); + } + + private int rmq(int v, int from, int to) { + STNode n = heap[v]; + + // If you did a range update that contained this node, you can infer the Product without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) { + return (to - from + 1) * n.pendingVal; + } + + if (contains(from, to, n.from, n.to)) { + return heap[v].mul; + } + + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftMul = rmq(2 * v, from, to); + int rightMul = rmq(2 * v + 1, from, to); + + return leftMul * rightMul; + } + + return 1; // neutral element + } + + /** + * Range Min Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @return min + */ + public int rMinQ(int from, int to) { + return rMinQ(1, from, to); + } + + private int rMinQ(int v, int from, int to) { + STNode n = heap[v]; + + + // If you did a range update that contained this node, you can infer the Min value without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) { + return n.pendingVal; + } + + if (contains(from, to, n.from, n.to)) { + return heap[v].min; + } + + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftMin = rMinQ(2 * v, from, to); + int rightMin = rMinQ(2 * v + 1, from, to); + + return Math.min(leftMin, rightMin); + } + + return 1000000000; // 1e9 to avoid overflow + } + + /** + * Range Max Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @author Diogo Peralta Cordeiro + * @return max + */ + public int rMaxQ(int from, int to) { + return rMaxQ(1, from, to); + } + + private int rMaxQ(int v, int from, int to) { + STNode n = heap[v]; + + // If you did a range update that contained this node, you can infer the Max value without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) + return n.pendingVal; + if (contains(from, to, n.from, n.to)) + return heap[v].max; + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftMax = rMaxQ(2 * v, from, to); + int rightMax = rMaxQ(2 * v + 1, from, to); + return Math.max(leftMax, rightMax); + } + return -1000000000; // 1e9 to avoid overflow + } + + /** + * Range Update Operation. + * With this operation you can update either one position or a range of positions with a given number. + * The update operations will update the less it can to update the whole range (Lazy Propagation). + * The values will be propagated lazily from top to bottom of the segment tree. + * This behavior is really useful for updates on portions of the array + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @param value value + */ + public void update(int from, int to, int value) { + update(1, from, to, value); + } + + private void update(int v, int from, int to, int value) { + + // The Node of the heap tree represents a range of the array with bounds: [n.from, n.to] + STNode n = heap[v]; + + /** + * If the updating-range contains the portion of the current Node We lazily update it. + * This means We do NOT update each position of the vector, but update only some temporal + * values into the Node; such values into the Node will be propagated down to its children only when they need to. + */ + if (contains(from, to, n.from, n.to)) { + change(n, value); + } + + if (n.size() == 1) return; + + if (intersects(from, to, n.from, n.to)) { + /** + * Before keeping going down to the tree We need to propagate the + * the values that have been temporally/lazily saved into this Node to its children + * So that when We visit them the values are properly updated + */ + propagate(v); + + update(2 * v, from, to, value); + update(2 * v + 1, from, to, value); + + n.sum = heap[2 * v].sum + heap[2 * v + 1].sum; + n.mul = heap[2 * v].mul * heap[2 * v + 1].mul; + n.min = Math.min(heap[2 * v].min, heap[2 * v + 1].min); + n.max = Math.max(heap[2 * v].max, heap[2 * v + 1].max); + } + } + + // Propagate temporal values to children + private void propagate(int v) { + STNode n = heap[v]; + + if (n.pendingVal != null) { + change(heap[2 * v], n.pendingVal); + change(heap[2 * v + 1], n.pendingVal); + n.pendingVal = null; //unset the pending propagation value + } + } + + // Save the temporal values that will be propagated lazily + private void change(STNode n, int value) { + n.pendingVal = value; + n.sum = n.size() * value; + n.mul = n.size() * value; + n.min = value; + n.max = value; + array[n.from] = value; + + } + + // Test if the range1 contains range2 + private boolean contains(int from1, int to1, int from2, int to2) { + return from2 >= from1 && to2 <= to1; + } + + // check inclusive intersection, test if range1[from1, to1] intersects range2[from2, to2] + private boolean intersects(int from1, int to1, int from2, int to2) { + return from1 <= from2 && to1 >= from2 // (.[..)..] or (.[...]..) + || from1 >= from2 && from1 <= to2; // [.(..]..) or [..(..).. + } + + // The Node class represents a partition range of the array. + static class STNode { + int sum, mul; + int min, max; + // Here we store the value that will be propagated lazily + Integer pendingVal = null; + int from; + int to; + + int size() { + return to - from + 1; + } + + } + +} diff --git a/ValueThenKeyComparator.java b/ValueThenKeyComparator.java new file mode 100644 index 0000000..4f949fe --- /dev/null +++ b/ValueThenKeyComparator.java @@ -0,0 +1,17 @@ +import java.util.Comparator; +import java.util.Map; + +// from: https://stackoverflow.com/a/3074324 +public class ValueThenKeyComparator, + V extends Comparable> + implements Comparator> { + + public int compare(Map.Entry a, Map.Entry b) { + int cmp1 = b.getValue().compareTo(a.getValue()); + if (cmp1 != 0) { + return cmp1; + } else { + return a.getKey().compareTo(b.getKey()); + } + } +} diff --git a/bfs_scc.java b/bfs_scc.java new file mode 100644 index 0000000..721929d --- /dev/null +++ b/bfs_scc.java @@ -0,0 +1,22 @@ +// Pre-Process answers with a BFS (only possible if the graph is undirected) +int[] answers = new int[n]; +ArrayDeque queue = new ArrayDeque<>(n); // Queue +for (int s = n-1; s >= 0; --s) +{ + if (answers[s] < s) + answers[s] = s; + queue.addFirst(s); + g.seen[s] = true; + while(!queue.isEmpty()) + { + int u = queue.removeLast(); + this.edges(u).forEach((w) -> { + if (!g.verts[w].seen) + { + queue.addFirst(w); + g.seen[w] = true; + answers[w] = s; + } + } + } +} diff --git a/bfs_shortest_path.java b/bfs_shortest_path.java new file mode 100644 index 0000000..54bc17d --- /dev/null +++ b/bfs_shortest_path.java @@ -0,0 +1,54 @@ +public class bfs_shortest_path +{ + public static void main (String[] args) + { + int n_nodes = 42; + boolean[] come_from = new boolean[n_nodes]; + DirectedMultiGraph graph = new DirectedMultiGraph(n_nodes, true); + + // Input + Scanner stdin = new Scanner(System.in); + int a = stdin.nextInt(), b, graph_root = a; + while ((b = stdin.nextInt()) != 0) + { + graph.link_first(a, b); + + a = b; + } + int destination = a; + + // BFS + ArrayDeque to_explore = new ArrayDeque<>(); // Queue + to_explore.addFirst(graph_root); + graph.seen[graph_root] = true; + while (!to_explore.isEmpty()) + { + int u = to_explore.removeLast(); + this.edges(u).forEach((w) -> + { + if (!g.seen[w]) + { + to_explore.addFirst(w); + g.seen[w] = true; + come_from[w] = v; + } + } + } + + // Output + ArrayDeque path = new ArrayDeque<>(); + path.addFirst(destination); + while(path.getFirst() != graph_root) + { + path.addFirst(graph.verts[path.getFirst()].come_from); + } + System.out.println("Output:"); + for (int i : path) + { + System.out.println(i); + } + + // No leaks + stdin.close(); + } +} diff --git a/collections_count_if.java b/collections_count_if.java new file mode 100644 index 0000000..3c262b9 --- /dev/null +++ b/collections_count_if.java @@ -0,0 +1,56 @@ +package ProgrammingChallenges.Uva; + +import java.util.*; +import java.util.function.IntPredicate; + +class UVA11286 { + static final int modules_per_term = 5; + + public static void + main(String[] args) { + Scanner stdin = new Scanner(System.in); + + // + Map, Integer> freshers_modules = new HashMap<>(); + + while (stdin.hasNext()) { + int number_of_freshers = stdin.nextInt(); + if (number_of_freshers == 0) { + break; // This was the last test case + } + freshers_modules.clear(); // Reset our data structure + + for (int i = 0; i < number_of_freshers; ++i) { + List modules = new ArrayList<>(); + for (int j = 0; j < modules_per_term; ++j) { + int x = stdin.nextInt(); + modules.add(x); + } + Collections.sort(modules); + freshers_modules.merge(modules, 1, Integer::sum); + } + + // Most popular pair + Map.Entry, Integer> most_popular_module = Collections.max(freshers_modules.entrySet(), Map.Entry.comparingByValue()); + // How many are as popular? + int max_students = most_popular_module.getValue(); + int number_of_equally_popular_modules = collections_count_if(freshers_modules.values(), (a) -> a == max_students); + // This is the sh1ttiest prompt ever... + //System.out.println("max_students = "+max_students+"\nnumber_of_equally_popular_modules = "+number_of_equally_popular_modules+"\nnumber_of_freshers = "+number_of_freshers); + System.out.println(max_students * number_of_equally_popular_modules); + } + stdin.close(); + } + + public static int + collections_count_if(Collection coll, IntPredicate op) { + int count = 0; + for (Integer v : coll) { + if (op.test((v))) { + ++count; + } + } + return count; + } + +} diff --git a/knapsack.java b/knapsack.java new file mode 100644 index 0000000..818549a --- /dev/null +++ b/knapsack.java @@ -0,0 +1,65 @@ +import java.util.Arrays; + +public class DAA011 { + public static void + main(String[] args) + { + FastScanner stdin = new FastScanner(System.in); + int n = stdin.nextInt(); + int[] dist = new int[n]; + int max = 0; + + for (int i = 0; i < n; ++i) { + dist[i] = stdin.nextInt(); + max += dist[i]; + } + + for (int p = stdin.nextInt(); p > 0; --p) { + FastPrint.out.println(cond_bsearch(dist, 0, max, stdin.nextInt())); + } + + FastPrint.out.close(); + } + + public static int + cond_bsearch(int[] haystack, int l, int r, int k) + { + //System.out.println(Arrays.toString(haystack)); + //System.out.println("l: "+l+" | r: "+r+" | k: "+k); + while (l < r) { + int mid = l + (r - l) / 2; + + if (cond(haystack, mid, k)) { + r = mid; + } else { + l = mid + 1; + } + } + + //System.out.println("l: "+l+" | r: "+r+" | k: "+k); + //return cond(haystack, l, k) ? l : -1; + return l; + } + + public static boolean + cond(int[] dist, int needle, int k) + { + //System.out.println("needle: "+needle); + int acc = 0; + int partitions = 0; + for (int i : dist) { // 10 + acc += i; // 18 + if (acc > needle) { // 18 > 8 = true + acc = i; // This one isn't part of the partition we've just created = 10 + if (i > needle) return false; + if (++partitions > k) { //part = 7 > 10 = false + //System.out.println("last number of partitions: "+partitions); + return false; // early break to save time + } + } + //System.out.println("i: "+i+" | acc: "+acc+" | part: "+partitions); + } + //System.out.println("last_number of partitions: "+partitions); + return partitions < k; + } +} diff --git a/minimum_gap_schedulling.java b/minimum_gap_schedulling.java new file mode 100644 index 0000000..25d8d28 --- /dev/null +++ b/minimum_gap_schedulling.java @@ -0,0 +1,85 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Activity implements Comparable +{ + int start, end; + + Activity(int start, int end) + { + this.start = start; + this.end = end; + } + + @Override + public String toString() { + return "["+start+","+end+"]"; + } + + @Override + // Early Start + // Longest size + public int compareTo(Activity b) { + int early_start = Integer.compare(this.start, b.start); + if (early_start == 0) + return Integer.compare(b.end-b.start, this.end-this.start); + return early_start; + } + + public boolean + intersects (Activity b) + { + return this.start <= b.start || + b.end < this.start; + } +} + +class +DAA013 +{ + public static void + main (String[] args) + { + FastScanner stdin = new FastScanner(System.in); + + int M = stdin.nextInt(), // tamanho do segmento a cobrir + N = stdin.nextInt(); // qtd de segmentos + + Activity[] acts = new Activity[N]; + for (int i = 0; i < N; ++i) + { + int l = stdin.nextInt(), + r = stdin.nextInt(); + acts[i] = new Activity(l, r); + } + + // Sort them + Arrays.sort(acts); + //System.out.println(Arrays.toString(acts)); + + // Cobertura mínima + int end = 0; + Activity x = acts[0]; + List path = new ArrayList<>(); + while (end < M) + { + for (Activity candidate : acts) + { + if (candidate.start <= end) + { + if (candidate.end >= x.end) + { + x = candidate; + } + } + } + end = x.end; + path.add(x); + } + //System.out.println(path); + + FastPrint.out.println(path.size()); + FastPrint.out.close(); + } +}