This commit is contained in:
Diogo Cordeiro 2021-02-03 23:38:26 +00:00
parent 6fef06fdef
commit fc5aee5646
18 changed files with 1532 additions and 1 deletions

83
Couple.java Normal file
View File

@ -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<F, S> {
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 <A, B> Couple<A, B> create(A a, B b) {
return new Couple<A, B>(a, b);
}
}

129
DFS.java Normal file
View File

@ -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<String, Integer> 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<int> 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<Integer>... 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<Integer> 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();
}
}

85
DirectedMultiGraph.java Normal file
View File

@ -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 <diogo@fc.up.pt>
*/
public class
DirectedMultiGraph
{
private final List<LinkedList<Integer>> 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<Integer>
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];
}
}

275
DirectedWeightedGraph.java Normal file
View File

@ -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 <diogo@fc.up.pt>
*/
public class
DirectedWeightedGraph<T>
{
private final List<LinkedList<Integer>> edges;
private final Map<String, List<T>> 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<Integer>
edges (int u)
{
return this.edges.get(u);
}
// O(1) to get the weights list
public List<T>
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<Object>
int_dijkstra(int s) {
/* Set Data Structures */
int[] dist = new int[this.n_nodes];
List<List<Integer>> 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<Integer> 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<Object>
double_dijkstra(int s) {
/* Set Data Structures */
double[] dist = new double[this.n_nodes];
List<List<Integer>> 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<Integer> 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<Integer> 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<Integer> 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;
}
}

10
FastPrint.java Normal file
View File

@ -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));
}

61
FastScanner.java Normal file
View File

@ -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;
}
}

90
FloydWarshall.java Normal file
View File

@ -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<Integer> 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] + ".");
}

26
InsertSort.java Normal file
View File

@ -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));
}
}

34
Johnson.java Normal file
View File

@ -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<Integer> 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;
}

91
LIS.java Normal file
View File

@ -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();
}
}

View File

@ -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)

318
SegmentTree.java Normal file
View File

@ -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.
* <p>
* 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.
* <p>
* Example:
* <p>
* 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)
* <p>
* 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
* <p>
* 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
* <p>
* Time-Complexity: O(log(n))
*
* @param from from index
* @param to to index
* @author Diogo Peralta Cordeiro <diogo@fc.up.pt>
* @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
* <p>
* 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
* <p>
* Time-Complexity: O(log(n))
*
* @param from from index
* @param to to index
* @author Diogo Peralta Cordeiro <diogo@fc.up.pt>
* @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
* <p>
* 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;
}
}
}

View File

@ -0,0 +1,17 @@
import java.util.Comparator;
import java.util.Map;