rest of silver

This commit is contained in:
Benjamin Qi 2020-07-14 14:21:06 -04:00
parent 642476d8cf
commit c0cc5c8552
6 changed files with 210 additions and 63 deletions

View file

@ -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 = {
}
};
<problems-list problems={metadata.problems.sample} />
## Resources
<resources>
@ -64,14 +61,32 @@ export const metadata = {
<resource source="TC" title="Graphs Section 2" url="introduction-to-graphs-and-their-data-structures-section-2"></resource>
</resources>
## Tree Problems
## Counting Connected Components
<problems-list problems={metadata.problems.tree} />
<problems-list problems={metadata.problems.sample} />
## General Problems
### Implementation
(code?)
<IncompleteSection />
### Problems
<problems-list problems={metadata.problems.general} />
## Tree Problems
### Implementation
(code?)
<IncompleteSection />
### Problems
<problems-list problems={metadata.problems.tree} />
## 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
<resource source="cp-algo" title="Bipartite Check" url="graph/bipartite-check.html">Uses BFS, but DFS accomplishes the same task.</resource>
</resources>
### 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.
<LanguageSection>
<CPPSection>
<br />
```cpp
//UNTESTED
@ -110,6 +134,10 @@ void dfs(int node)
}
```
</CPPSection>
</LanguageSection>
### Problems
<problems-list problems={metadata.problems.bip} />

View file

@ -49,6 +49,8 @@ blue for nodes already visited, and uncolored for nodes not yet visited.
(tables)
<IncompleteSection />
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 (well 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
<LanguageSection>
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);
}
```
<CPPSection>
```cpp
int grid[MAXN][MAXM]; // the grid itself
@ -191,6 +160,52 @@ int main(){
}
```
</CPPSection>
<JavaSection>
```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);
}
```
</JavaSection>
</LanguageSection>
## Problems
<problems-list problems={metadata.problems.general} />

View file

@ -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**.
<resource source="CPH" title="16.3, 16.4 - Successor Graphs"></resource>
</resources>
(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.
<LanguageSection>
<CPPSection>
```cpp
//UNTESTED
@ -71,6 +73,13 @@ int main()
}
```
</CPPSection>
</LanguageSection>
(floyd's algo?)
<IncompleteSection />
## Problems

View file

@ -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.
<LanguageSection>
<CPPSection>
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<end, start>`.
```cpp
// read in the input, store the events in pair<int, int>[] 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;
```
</CPPSection>
<JavaSection>
We'll be using the following static class to store each event:
```java
static class Event implements Comparable<Event>{
@ -149,7 +177,6 @@ static class Event implements Comparable<Event>{
}
```
<br />
```java
// read in the input, store the events in Event[] events.
@ -168,6 +195,11 @@ pw.println(ans);
pw.close();
```
</JavaSection>
</LanguageSection>
## 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.

View file

@ -53,6 +53,10 @@ Two pointers refers to iterating two monotonic pointers across an array to searc
<resource source="IUSACO" title="14.1 - Two Pointers"></resource>
</resources>
### Implementation
<IncompleteSection />
## Sliding Window
<problems-list problems={metadata.problems.slide} />
@ -68,6 +72,10 @@ To compute the sum in the range, instead of using a set, we can store a variable
<resource source="GFG" title="Window Sliding Technique" url="window-sliding-technique"> </resource>
</resources>
### Implementation
<IncompleteSection />
### Problems
<problems-list problems={metadata.problems.general} />

View file

@ -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).
<LanguageSection>
<CPPSection>
### [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
```
</CPPSection>
<JavaSection>
### 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
```
</JavaSection>
</LanguageSection>
## Queues
A queue is a First In First Out (FIFO) data structure that supports three operations, all in $O(1)$ time.
<LanguageSection>
<CPPSection>
### [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
```
</CPPSection>
<JavaSection>
### Java
- `add`: insertion at the back of the queue
@ -103,10 +123,18 @@ q.poll(); // [4, 3]
System.out.println(q.peek()); // 3
```
</JavaSection>
</LanguageSection>
## 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.
<LanguageSection>
<CPPSection>
### [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]
```
</CPPSection>
<JavaSection>
### 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/)
</JavaSection>
</LanguageSection>
## Priority Queues
<LanguageSection>
<CPPSection>
### [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]
```
<code-comment lang="java">
</CPPSection>
<JavaSection>
### Java
In Java, we delete and retrieve the element of **lowest** priority.
</code-comment>
```java
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
pq.add(7); // [7]
@ -169,6 +214,12 @@ pq.poll(); // [7, 5]
pq.add(6); // [7, 6, 5]
```
</JavaSection>
</LanguageSection>
## Monotonic Stack
<problems-list problems={metadata.problems.nearest} />
@ -184,6 +235,10 @@ To solve this, let's store a stack of pairs of `<value, index>` 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)
<IncompleteSection />
### Further Reading
<resources>