From c0cc5c85520f0b268db9c3a1c4d2495eab01cc95 Mon Sep 17 00:00:00 2001 From: Benjamin Qi Date: Tue, 14 Jul 2020 14:21:06 -0400 Subject: [PATCH] rest of silver --- content/4_Silver/DFS.mdx | 66 ++++++++++++++++------- content/4_Silver/Flood_Fill.mdx | 85 ++++++++++++++++++------------ content/4_Silver/Func_Graphs.mdx | 15 ++++-- content/4_Silver/Greedy.mdx | 36 ++++++++++++- content/4_Silver/Sliding.mdx | 8 +++ content/4_Silver/Stacks_Queues.mdx | 63 ++++++++++++++++++++-- 6 files changed, 210 insertions(+), 63 deletions(-) diff --git a/content/4_Silver/DFS.mdx b/content/4_Silver/DFS.mdx index bab294f..ca263ab 100644 --- a/content/4_Silver/DFS.mdx +++ b/content/4_Silver/DFS.mdx @@ -15,11 +15,22 @@ export const metadata = { sample: [ new Problem("CSES", "Building Roads", "1666", "Intro|Very Easy", false, ["DFS"]), ], + general: [ + new Problem("CF", "Bear & Friendship", "problemset/problem/771/A", "Easy", false, ["DFS"]), + new Problem("Silver", "Closing the Farm", "644", "Easy", false, ["DFS"]), + new Problem("Silver", "Moocast", "668", "Easy", false, ["DFS"]), + new Problem("Silver", "Fence Planning", "944", "Easy", false, ["DFS"]), + new Problem("Kattis", "Birthday Party", "birthday", "Easy", false, ["DFS"], "DFS with each edge removed"), + new Problem("Silver", "Mootube", "788", "Easy", false, ["Tree", "DFS"]), + new Problem("CF", "PolandBall & Forest", "problemset/problem/755/C", "Easy", false, ["Tree", "DFS"]), + new Problem("Silver", "Milk Visits", "968", "Normal", false, ["DFS"]), + new Problem("Silver", "Milk Pails", "620", "Normal", false, ["DFS"]), + new Problem("Silver", "Wormhole Sort", "992", "Normal", false, ["DFS", "Binary Search"]), + new Problem("Silver", "Moo Particle", "1040", "Normal", false, ["Sorting"]), + ], tree: [ new Problem("CSES", "Subordinates", "1674", "Very Easy", false, ["Tree", "DFS"]), - new Problem("Silver", "Mootube", "788", "Easy", false, ["Tree", "DFS"]), new Problem("CF", "Journey", "contest/839/problem/C", "Easy", false, ["Tree", "DFS"]), - new Problem("CF", "PolandBall & Forest", "problemset/problem/755/C", "Easy", false, ["Tree", "DFS"]), new Problem("CSES", "Tree Diameter", "1131", "Normal", false, ["Tree", "DFS"]), new Problem("CSES", "Tree Distances I", "1132", "Normal", false, ["Tree", "DFS"]), new Problem("CSES", "Tree Distances II", "1133", "Normal", false, ["Tree", "DFS"]), @@ -28,17 +39,6 @@ export const metadata = { new Problem("HE", "Birthday Gifts", "https://www.hackerearth.com/practice/math/combinatorics/inclusion-exclusion/practice-problems/algorithm/mancunian-and-birthday-gifts-d44faa15/description/", "Normal", false, ["Tree", "PIE"], ""), new Problem("CSA", "Tree Construction", "contest/860/problem/D", "Hard", false, ["Tree", "DFS"], "several cases"), ], - general: [ - new Problem("CF", "Bear & Friendship", "problemset/problem/771/A", "Easy", false, ["DFS"]), - new Problem("Silver", "Closing the Farm", "644", "Easy", false, ["DFS"]), - new Problem("Silver", "Moocast", "668", "Easy", false, ["DFS"]), - new Problem("Silver", "Fence Planning", "944", "Easy", false, ["DFS"]), - new Problem("Kattis", "Birthday Party", "birthday", "Easy", false, ["DFS"], "DFS with each edge removed"), - new Problem("Silver", "Milk Visits", "968", "Normal", false, ["DFS"]), - new Problem("Silver", "Milk Pails", "620", "Normal", false, ["DFS"]), - new Problem("Silver", "Wormhole Sort", "992", "Normal", false, ["DFS", "Binary Search"]), - new Problem("Silver", "Moo Particle", "1040", "Normal", false, ["Sorting"]), - ], bipsample: [ new Problem("CSES", "Building Teams", "1668", "Easy", false, ["Bipartite"]), ], @@ -49,9 +49,6 @@ export const metadata = { } }; - - - ## Resources @@ -64,14 +61,32 @@ export const metadata = { -## Tree Problems +## Counting Connected Components - + -## General Problems +### Implementation + +(code?) + + + +### Problems +## Tree Problems + +### Implementation + +(code?) + + + +### Problems + + + ## Graph Two-Coloring *Graph two-coloring* refers to assigning a boolean value to each node of the graph, dictated by the edge configuration. @@ -87,8 +102,17 @@ The most common example of a two-colored graph is a *bipartite graph*, in which Uses BFS, but DFS accomplishes the same task. + +### Implementation + The idea is that we can arbitrarily label a node and then run DFS. Every time we visit a new (unvisited) node, we set its color based on the edge rule. When we visit a previously visited node, check to see whether its color matches the edge rule. For example, an implementation of coloring a bipartite graph is shown below. + + + + +
+ ```cpp //UNTESTED @@ -110,6 +134,10 @@ void dfs(int node) } ``` +
+ +
+ ### Problems diff --git a/content/4_Silver/Flood_Fill.mdx b/content/4_Silver/Flood_Fill.mdx index 636fc0f..c17b51c 100644 --- a/content/4_Silver/Flood_Fill.mdx +++ b/content/4_Silver/Flood_Fill.mdx @@ -49,6 +49,8 @@ blue for nodes already visited, and uncolored for nodes not yet visited. (tables) + + As opposed to an explicit graph where the edges are given, a grid is an implicit graph. This means that the neighbors are just the nodes directly adjacent in the four cardinal directions. @@ -115,42 +117,9 @@ This means that we want to recursively call the search function from the squares below, and to the left and right of our current square. The algorithm to find the size of a connected component in a grid using floodfill is as follows (we’ll also maintain a 2D visited array). -```java -static int[][] grid; // the grid itself -static int n, m; // grid dimensions, rows and columns -static boolean[][] visited; // keeps track of which nodes have been visited -static int currentSize = 0; // reset to 0 each time we start a new component + -public static void main(String[] args){ - /** - * input code and other problem-specific stuff here - */ - for(int i = 0; i < n; i++){ - for(int j = 0; j < m; j++){ - if(!visited[i][j]){ - currentSize = 0; - floodfill(i, j, grid[i][j]); - // start a floodfill if the square hasn't already been visited, - // and then store or otherwise use the component size - // for whatever it's needed for - } - } - } -} - -static void floodfill(int r, int c, int color){ - if(r < 0 || r >= n || c < 0 || c >= m) return; // if outside grid - if(grid[r][c] != color) return; // wrong color - if(visited[r][c]) return; // already visited this square - visited[r][c] = true; // mark current square as visited - currentSize++; // increment the size for each square we visit - // recursively call floodfill for neighboring squares - floodfill(r, c+1, color); - floodfill(r, c-1, color); - floodfill(r-1, c, color); - floodfill(r+1, c, color); -} -``` + ```cpp int grid[MAXN][MAXM]; // the grid itself @@ -191,6 +160,52 @@ int main(){ } ``` + + + + +```java +static int[][] grid; // the grid itself +static int n, m; // grid dimensions, rows and columns +static boolean[][] visited; // keeps track of which nodes have been visited +static int currentSize = 0; // reset to 0 each time we start a new component + +public static void main(String[] args){ + /** + * input code and other problem-specific stuff here + */ + for(int i = 0; i < n; i++){ + for(int j = 0; j < m; j++){ + if(!visited[i][j]){ + currentSize = 0; + floodfill(i, j, grid[i][j]); + // start a floodfill if the square hasn't already been visited, + // and then store or otherwise use the component size + // for whatever it's needed for + } + } + } +} + +static void floodfill(int r, int c, int color){ + if(r < 0 || r >= n || c < 0 || c >= m) return; // if outside grid + if(grid[r][c] != color) return; // wrong color + if(visited[r][c]) return; // already visited this square + visited[r][c] = true; // mark current square as visited + currentSize++; // increment the size for each square we visit + // recursively call floodfill for neighboring squares + floodfill(r, c+1, color); + floodfill(r, c-1, color); + floodfill(r-1, c, color); + floodfill(r+1, c, color); +} +``` + + + + + + ## Problems \ No newline at end of file diff --git a/content/4_Silver/Func_Graphs.mdx b/content/4_Silver/Func_Graphs.mdx index 69d0f28..2bce4ca 100644 --- a/content/4_Silver/Func_Graphs.mdx +++ b/content/4_Silver/Func_Graphs.mdx @@ -14,7 +14,7 @@ import { Problem } from "../models"; export const metadata = { problems: { sample: [ - new Problem("CF", "Div 2 B - Badge", "contest/1020/problem/B", "Intro", false, ["Func Graph"], "Try to solve the problem in $O(N)$!"), + new Problem("CF", "Div 2 B - Badge", "contest/1020/problem/B", "Very Easy", false, ["Func Graph"], "Try to solve the problem in $O(N)$!"), ], general: [ new Problem("Silver", "The Bovine Shuffle", "764", "Normal", false, ["Func Graph"], "Try to solve the problem in $O(N)$!"), @@ -39,12 +39,14 @@ Aka **successor graph**. -(floyd's algo?) - ## Implementation The following sample code counts the number of cycles in such a graph. The "stack" contains nodes that can reach the current node. If the current node points to a node `v` on the stack (`on_stack[v]` is true), then we know that a cycle has been created. However, if the current node points to a node `v` that has been previously visited but is not on the stack, then we know that the current chain of nodes points into a cycle that has already been considered. + + + + ```cpp //UNTESTED @@ -71,6 +73,13 @@ int main() } ``` + + + + +(floyd's algo?) + + ## Problems diff --git a/content/4_Silver/Greedy.mdx b/content/4_Silver/Greedy.mdx index 93970dc..0cdbb61 100644 --- a/content/4_Silver/Greedy.mdx +++ b/content/4_Silver/Greedy.mdx @@ -135,7 +135,35 @@ Instead, we can select the event that ends as early as possible. This correctly In fact, this algorithm always works. A brief explanation of correctness is as follows. If we have two events $E_1$ and $E_2$, with $E_2$ ending later than $E_1$, then it is always optimal to select $E_1$. This is because selecting $E_1$ gives us more choices for future events. If we can select an event to go after $E_2$, then that event can also go after $E_1$, because $E_1$ ends first. Thus, the set of events that can go after $E_2$ is a subset of the events that can go after $E_1$, making $E_1$ the optimal choice. -For the following code, let's say we have the array `events` of events, which each contain a start and an end point. We'll be using the following static class to store each event: +For the following code, let's say we have the array `events` of events, which each contain a start and an end point. + + + + + +We'll be using the C++ built in container pair to store each event. Note that since the standard sort in C++ sorts by first element, we will store each event as `pair`. + +```cpp +// read in the input, store the events in pair[] events. +sort(events, events + n); // sorts by first element (ending time) +int currentEventEnd = -1; // end of event currently attending +int ans = 0; // how many events were attended? +for(int i = 0; i < n; i++){ // process events in order of end time + if(events[i].second >= currentEventEnd){ // if event can be attended + // we know that this is the earliest ending event that we can attend + // because of how the events are sorted + currentEventEnd = events[i].first; + ans++; + } +} +cout << ans << endl; +``` + + + + + +We'll be using the following static class to store each event: ```java static class Event implements Comparable{ @@ -149,7 +177,6 @@ static class Event implements Comparable{ } ``` -
```java // read in the input, store the events in Event[] events. @@ -168,6 +195,11 @@ pw.println(ans); pw.close(); ``` +
+ +
+ + ## When Greedy Fails We'll provide a few common examples of when greedy fails, so that you can avoid falling into obvious traps and wasting time getting wrong answers in contest. diff --git a/content/4_Silver/Sliding.mdx b/content/4_Silver/Sliding.mdx index 643e639..0daf8cc 100644 --- a/content/4_Silver/Sliding.mdx +++ b/content/4_Silver/Sliding.mdx @@ -53,6 +53,10 @@ Two pointers refers to iterating two monotonic pointers across an array to searc +### Implementation + + + ## Sliding Window @@ -68,6 +72,10 @@ To compute the sum in the range, instead of using a set, we can store a variable +### Implementation + + + ### Problems diff --git a/content/4_Silver/Stacks_Queues.mdx b/content/4_Silver/Stacks_Queues.mdx index af77fbe..d12994e 100644 --- a/content/4_Silver/Stacks_Queues.mdx +++ b/content/4_Silver/Stacks_Queues.mdx @@ -35,6 +35,10 @@ export const metadata = { A stack is a **Last In First Out** (LIFO) data structure that supports three operations, all in $O(1)$ time. Think of it like a real-world stack of papers (or cards). + + + + ### [C++](http://www.cplusplus.com/reference/stack/stack/) - `push`: adds an element to the top of the stack @@ -51,6 +55,10 @@ s.pop(); // [1, 13] cout << s.size() << endl; // 2 ``` + + + + ### Java - `push`: adds an element to the top of the stack @@ -67,10 +75,18 @@ s.pop(); // [1, 13] System.out.println(s.size()); // 2 ``` + + + + ## Queues A queue is a First In First Out (FIFO) data structure that supports three operations, all in $O(1)$ time. + + + + ### [C++](http://www.cplusplus.com/reference/queue/queue/) - `push`: insertion at the back of the queue @@ -86,6 +102,10 @@ q.pop(); // [4, 3] cout << q.front() << endl; // 3 ``` + + + + ### Java - `add`: insertion at the back of the queue @@ -103,10 +123,18 @@ q.poll(); // [4, 3] System.out.println(q.peek()); // 3 ``` + + + + ## Deques A **deque** (usually pronounced "deck") stands for double ended queue and is a combination of a stack and a queue, in that it supports $O(1)$ insertions and deletions from both the front and the back of the deque. Not very common in Bronze / Silver. + + + + ### [C++](http://www.cplusplus.com/reference/deque/deque/) The four methods for adding and removing are `push_back`, `pop_back`, `push_front`, and `pop_front`. @@ -121,6 +149,10 @@ d.push_front(1); // [1, 3, 7] d.pop_back(); // [1, 3] ``` + + + + ### Java In Java, the deque class is called `ArrayDeque`. The four methods for adding and removing are `addFirst` , `removeFirst`, `addLast`, and `removeLast`. @@ -135,7 +167,17 @@ deque.addFirst(1); // [1, 3, 7] deque.removeLast(); // [1, 3] ``` -## [Priority Queues](http://www.cplusplus.com/reference/queue/priority_queue/) + + + + +## Priority Queues + + + + + +### [C++](http://www.cplusplus.com/reference/queue/priority_queue/) A priority queue supports the following operations: insertion of elements, deletion of the element considered highest priority, and retrieval of the highest priority element, all in $O(\log n)$ time according to the number of elements in the priority queue. Priority is based on a comparator function. The priority queue is one of the most important data structures in competitive programming, so make sure you understand how and when to use it. @@ -151,12 +193,15 @@ pq.pop(); // [1, 2] pq.push(6); // [1, 2, 6] ``` - + + + + + +### Java In Java, we delete and retrieve the element of **lowest** priority. - - ```java PriorityQueue pq = new PriorityQueue(); pq.add(7); // [7] @@ -169,6 +214,12 @@ pq.poll(); // [7, 5] pq.add(6); // [7, 6, 5] ``` + + + + + + ## Monotonic Stack @@ -184,6 +235,10 @@ To solve this, let's store a stack of pairs of `` and iterate over The stack we used is called a **monotonic stack** because we keep popping off the top element of the stack which maintains it's monotonicity (the same property needed for algorithms like binary search) because the elements in the stack are increasing. +(add code) + + + ### Further Reading