From 8e180758332a877c4e7eff475e5f921192b913b9 Mon Sep 17 00:00:00 2001 From: Atulbedwal <76045376+Atulbedwal@users.noreply.github.com> Date: Tue, 25 Jun 2024 00:57:42 +0530 Subject: [PATCH 01/86] Update strong-orientation.md --- src/graph/strong-orientation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/strong-orientation.md b/src/graph/strong-orientation.md index 50397b287..69a7b37d9 100644 --- a/src/graph/strong-orientation.md +++ b/src/graph/strong-orientation.md @@ -78,7 +78,7 @@ void find_bridges(int v) { bridge_cnt++; } } else { - low[v] = min(low[v], low[nv]); + low[v] = min(low[v], tin[nv]); } } } From 170845165a6dbd8b15fedfc668c2afb8217fec7d Mon Sep 17 00:00:00 2001 From: Prithvi-Rao Date: Fri, 18 Oct 2024 21:48:55 +0530 Subject: [PATCH 02/86] Added Simulated Annealing --- src/navigation.md | 1 + src/num_methods/simulated_annealing.md | 159 +++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 src/num_methods/simulated_annealing.md diff --git a/src/navigation.md b/src/navigation.md index 29d6a94cb..6b7caef53 100644 --- a/src/navigation.md +++ b/src/navigation.md @@ -110,6 +110,7 @@ search: - [Binary Search](num_methods/binary_search.md) - [Ternary Search](num_methods/ternary_search.md) - [Newton's method for finding roots](num_methods/roots_newton.md) + - [Simulated Annealing](num_methods/simulated_annealing.md) - Integration - [Integration by Simpson's formula](num_methods/simpson-integration.md) - Geometry diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md new file mode 100644 index 000000000..42879fe99 --- /dev/null +++ b/src/num_methods/simulated_annealing.md @@ -0,0 +1,159 @@ +--- +tags: + - Original +--- + +# Simulated Annealing + +**Simulated Annealing (SA)** is a randomized algorithm, which approximates the global optimum of a function. It's called a randomized algorithm, because it employs a certain amount of randomness in its search and thus its output can vary for the same input. + +## The Problem + +We are given a function $ E(s) $, which calculates the potential of the state $ s $. We are tasked with finding the state $ s_{best} $ at which $ E(s) $ is minimized. SA is suited for problems where the states are discrete and $ E(s) $ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). + +### Travelling Salesman Problem (TSP) + +You are given a set of nodes in 2 dimensional space. Each node is characterised by its $ x $ and $ y $ coordinates. Your task is to find the an ordering of the nodes, which will minimise the distance to be travelled when visiting these nodes in that order. + +### State + +State space is the collection of all possible values that can be taken by the independent variables. +A State is a unique point in the state space of the problem. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a State. + +### Neighbouring State + +It is a State in the State space which is close to the previous State. This usually means that we can obtain the neighbouring State from the original State using a simple transform. In the case of the Travelling salesman problem, a neighbouring state is obtained by randomly choosing 2 nodes, and swapping their positions in the current state. + +### E(s) + +$ E(s) $ is the function which needs to be minimised (or maximised). It maps every state to a real number. In the case of TSP, $ E(s) $ returns the distance of travelling one full circle in the order of nodes in the state. + +## Approach + +We start of with a random state $ s $. In every step, we choose a neighbouring state $ s_{next} $ of the current state $ s $. If $ E(s_{next}) < E(s) $, then we update $ s = s_{next} $. Otherwise, we use a probability acceptance function $ P(E(s),E(s_{next}),T) $ which decides whether we should move to $ s_{next} $ or stay at s. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to s_next. +At the same time we also keep a track of the best state $ s_{best} $ across all iterations. Proceed till convergence or time runs out. + + +## Probability Acceptance Function +$$ +P(E,E_{next},T) = + \begin{cases} + \text{True} &\quad\text{if } \exp{\frac{-(E_{next}-E)}{T}} \ge random(0,1) \\ + \text{False} &\quad\text{otherwise}\\ + \end{cases} + +$$ +This function takes in the current state, the next state and the Temperature , returning a boolean value, which tells our search whether it should move to $ s_{next} $ or stay at s. Note that for $E_{next} < E$ , this function will always return True. + +```cpp +bool P(double E,double E_next,double T){ + double e = 2.71828; + double prob = (double)rand()/RAND_MAX; // Generate a random number between 0 and 1 + if(pow(e,-(E_next-E)/T) > prob) return true; + else return false; +} +``` +## Code Template + +```cpp +class state{ + public: + state(){ + // Generate the initial state + } + state next(){ + state next; + next = s; + // Make changes to the state "next" and then return it + return next; + } + double E(){ + // implement the cost function here + }; +}; + +int main(){ + double T = 1000; // Initial temperature + double u = 0.99; // decay rate + state s = state(); + state best = s; + double E = s.E(); + double E_next; + double E_best = E; + while (T > 1){ + state next = s.next(); + E_next = next.E(); + if(P(E,E_next,T)){ + s = next; + if(E_next < E_best){ + best = s; + E_best = E_next; + } + } + E = E_next; + T *= u; + } + cout << E_best << "\n"; + return 0; +} +``` +## How to use: +Fill in the state class functions as appropriate. If you are trying to find a global maxima and not a minima, ensure that the $ E() $ function returns negative of the function you are maximising and finally print out $ -E_{best} $. Set the below parameters as per your need. + +### Parameters +- T : Temperature. Set it to a higher value if you want the search to run for a longer time +- u : Decay. Decides the rate of cooling. A slower cooling rate (larger value of u) usually gives better results. Ensure $u < 1$. + +The number of iterations the loop will run for is given by the expression +$$ +N = \lceil -\log_{u}{T} \rceil +$$ + +To see the effect of decay rate on solution results, run simulated annealing for decay rates 0.95 , 0.97 and 0.99 and see the difference. + +### Example State class for TSP +```cpp +class state{ + public: + vector> points; + + state(){ // Initial random order of points + points = {{0,0},{2,2},{0,2},{2,0},{0,1},{1,2},{2,1},{1,0}}; + } + state next(){ // picks 2 random indices and swaps them + state s_next; + s_next.points = points; + int a = ((rand()*points.size())/RAND_MAX); + int b = ((rand()*points.size())/RAND_MAX); + pair t = s_next.points[a]; + s_next.points[a] = s_next.points[b]; + s_next.points[b] = t; + return s_next; + } + + double euclidean(pair a, pair b){ // return euclidean distance between 2 points + return pow(pow((a.first-b.first),2)+pow((a.second-b.second),2),0.5); + } + double E(){ // calculates the round cost of travelling one full circle. + double dist = 0; + bool first = true; + int n = points.size(); + for(int i = 0;i < n; i++){ + dist += euclidean(points[i],points[(i+1)%n]); + } + return dist; + }; +}; +``` + +## Extra Modifications to the Algorithm: + +- Add a time based exit condition to the while loop to prevent TLE +- You can replace the e value in the Probability Acceptance function to any real number > 1. For a given $ E_{next} - E > 0 $, a higher e value reduces the chance of accepting that state and a smaller e value, increases it. + + +## Problems + +- https://usaco.org/index.php?page=viewproblem2&cpid=698 +- https://codeforces.com/contest/1556/problem/H +- https://atcoder.jp/contests/intro-heuristics/tasks/intro_heuristics_a \ No newline at end of file From 1eb4b14898ec98310b15c19d9aff20915f9f66f9 Mon Sep 17 00:00:00 2001 From: Prithvi-Rao Date: Sat, 19 Oct 2024 11:11:24 +0530 Subject: [PATCH 03/86] Formatting --- README.md | 1 + src/num_methods/simulated_annealing.md | 36 ++++++++++++-------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 31ce219bc..87fce368e 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Compiled pages are published at [https://cp-algorithms.com/](https://cp-algorith ### New articles +- (19 October 2024) [Simulated Annealing](https://cp-algorithms.com/num_methods/simulated_annealing.html) - (12 July 2024) [Manhattan distance](https://cp-algorithms.com/geometry/manhattan-distance.html) - (8 June 2024) [Knapsack Problem](https://cp-algorithms.com/dynamic_programming/knapsack.html) - (28 January 2024) [Introduction to Dynamic Programming](https://cp-algorithms.com/dynamic_programming/intro-to-dp.html) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index 42879fe99..33dee6449 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -9,11 +9,11 @@ tags: ## The Problem -We are given a function $ E(s) $, which calculates the potential of the state $ s $. We are tasked with finding the state $ s_{best} $ at which $ E(s) $ is minimized. SA is suited for problems where the states are discrete and $ E(s) $ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). +We are given a function $E(s)$, which calculates the potential of the state $s$. We are tasked with finding the state $s_{best}$ at which $E(s)$ is minimized. SA is suited for problems where the states are discrete and $E(s)$ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). ### Travelling Salesman Problem (TSP) -You are given a set of nodes in 2 dimensional space. Each node is characterised by its $ x $ and $ y $ coordinates. Your task is to find the an ordering of the nodes, which will minimise the distance to be travelled when visiting these nodes in that order. +You are given a set of nodes in 2 dimensional space. Each node is characterised by its $x$ and $y$ coordinates. Your task is to find the an ordering of the nodes, which will minimise the distance to be travelled when visiting these nodes in that order. ### State @@ -26,12 +26,12 @@ It is a State in the State space which is close to the previous State. This usua ### E(s) -$ E(s) $ is the function which needs to be minimised (or maximised). It maps every state to a real number. In the case of TSP, $ E(s) $ returns the distance of travelling one full circle in the order of nodes in the state. +$E(s)$ is the function which needs to be minimised (or maximised). It maps every state to a real number. In the case of TSP, $E(s)$ returns the distance of travelling one full circle in the order of nodes in the state. ## Approach -We start of with a random state $ s $. In every step, we choose a neighbouring state $ s_{next} $ of the current state $ s $. If $ E(s_{next}) < E(s) $, then we update $ s = s_{next} $. Otherwise, we use a probability acceptance function $ P(E(s),E(s_{next}),T) $ which decides whether we should move to $ s_{next} $ or stay at s. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to s_next. -At the same time we also keep a track of the best state $ s_{best} $ across all iterations. Proceed till convergence or time runs out. +We start of with a random state $s$. In every step, we choose a neighbouring state $s_{next}$ of the current state $s$. If $E(s_{next}) < E(s)$, then we update $s = s_{next}$. Otherwise, we use a probability acceptance function $P(E(s),E(s_{next}),T)$ which decides whether we should move to $s_{next}$ or stay at s. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to s_next. +At the same time we also keep a track of the best state $s_{best}$ across all iterations. Proceed till convergence or time runs out. ## Probability Acceptance Function @@ -41,9 +41,8 @@ P(E,E_{next},T) = \text{True} &\quad\text{if } \exp{\frac{-(E_{next}-E)}{T}} \ge random(0,1) \\ \text{False} &\quad\text{otherwise}\\ \end{cases} - $$ -This function takes in the current state, the next state and the Temperature , returning a boolean value, which tells our search whether it should move to $ s_{next} $ or stay at s. Note that for $E_{next} < E$ , this function will always return True. +This function takes in the current state, the next state and the Temperature , returning a boolean value, which tells our search whether it should move to $s_{next}$ or stay at s. Note that for $E_{next} < E$ , this function will always return True. ```cpp bool P(double E,double E_next,double T){ @@ -72,13 +71,12 @@ class state{ }; }; -int main(){ - double T = 1000; // Initial temperature - double u = 0.99; // decay rate +pair simAnneal(){ state s = state(); state best = s; - double E = s.E(); - double E_next; + double T = 1000; // Initial temperature + double u = 0.99; // decay rate + double E = s.E(),E_next; double E_best = E; while (T > 1){ state next = s.next(); @@ -93,12 +91,12 @@ int main(){ E = E_next; T *= u; } - cout << E_best << "\n"; - return 0; + return {E_best,best}; } + ``` ## How to use: -Fill in the state class functions as appropriate. If you are trying to find a global maxima and not a minima, ensure that the $ E() $ function returns negative of the function you are maximising and finally print out $ -E_{best} $. Set the below parameters as per your need. +Fill in the state class functions as appropriate. If you are trying to find a global maxima and not a minima, ensure that the $E()$ function returns negative of the function you are maximising and finally print out $-E_{best}$. Set the below parameters as per your need. ### Parameters - T : Temperature. Set it to a higher value if you want the search to run for a longer time @@ -149,11 +147,11 @@ class state{ ## Extra Modifications to the Algorithm: - Add a time based exit condition to the while loop to prevent TLE -- You can replace the e value in the Probability Acceptance function to any real number > 1. For a given $ E_{next} - E > 0 $, a higher e value reduces the chance of accepting that state and a smaller e value, increases it. +- You can replace the e value in the Probability Acceptance function to any real number > 1. For a given $E_{next} - E > 0$, a higher e value reduces the chance of accepting that state and a smaller e value, increases it. ## Problems -- https://usaco.org/index.php?page=viewproblem2&cpid=698 -- https://codeforces.com/contest/1556/problem/H -- https://atcoder.jp/contests/intro-heuristics/tasks/intro_heuristics_a \ No newline at end of file +- [USACO Jan 2017 - Subsequence Reversal](https://usaco.org/index.php?page=viewproblem2&cpid=698) +- [Deltix Summer 2021 - DIY Tree](https://codeforces.com/contest/1556/problem/H) +- [AtCoder Contest Scheduling](https://atcoder.jp/contests/intro-heuristics/tasks/intro_heuristics_a) \ No newline at end of file From ebd3cdf18838fc6ca551bf646a647a4e3b885e28 Mon Sep 17 00:00:00 2001 From: Prithvi-Rao Date: Sat, 19 Oct 2024 11:18:54 +0530 Subject: [PATCH 04/86] fixed compile issue --- src/num_methods/simulated_annealing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index 33dee6449..6fca91cd8 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -116,7 +116,7 @@ class state{ vector> points; state(){ // Initial random order of points - points = {{0,0},{2,2},{0,2},{2,0},{0,1},{1,2},{2,1},{1,0}}; + points = {}; // Fill in some points to start with, or generate them randomly } state next(){ // picks 2 random indices and swaps them state s_next; From 9c81f7917ad11673fbab4be323b08043de8ea45a Mon Sep 17 00:00:00 2001 From: Prithvi-Rao Date: Tue, 22 Oct 2024 00:37:59 +0530 Subject: [PATCH 05/86] Elaborated temp --- src/num_methods/simulated_annealing.md | 47 ++++++++++++++++---------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index 6fca91cd8..1af1d49cd 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -9,7 +9,7 @@ tags: ## The Problem -We are given a function $E(s)$, which calculates the potential of the state $s$. We are tasked with finding the state $s_{best}$ at which $E(s)$ is minimized. SA is suited for problems where the states are discrete and $E(s)$ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). +We are given a function $E(s)$, which calculates the potential of the state $s$. We are tasked with finding the state $s_{best}$ at which $E(s)$ is minimized. **SA** is suited for problems where the states are discrete and $E(s)$ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). ### Travelling Salesman Problem (TSP) @@ -20,29 +20,43 @@ You are given a set of nodes in 2 dimensional space. Each node is characterised State space is the collection of all possible values that can be taken by the independent variables. A State is a unique point in the state space of the problem. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a State. -### Neighbouring State +### Neighbouring state -It is a State in the State space which is close to the previous State. This usually means that we can obtain the neighbouring State from the original State using a simple transform. In the case of the Travelling salesman problem, a neighbouring state is obtained by randomly choosing 2 nodes, and swapping their positions in the current state. +It is a state in the state space which is close to the previous state. This usually means that we can obtain the neighbouring state from the original state using a simple transform. In the case of the Travelling Salesman Problem, a neighbouring state is obtained by randomly choosing 2 nodes, and swapping their positions in the current state. -### E(s) +### The Energy Function E(s) $E(s)$ is the function which needs to be minimised (or maximised). It maps every state to a real number. In the case of TSP, $E(s)$ returns the distance of travelling one full circle in the order of nodes in the state. -## Approach +## The Approach -We start of with a random state $s$. In every step, we choose a neighbouring state $s_{next}$ of the current state $s$. If $E(s_{next}) < E(s)$, then we update $s = s_{next}$. Otherwise, we use a probability acceptance function $P(E(s),E(s_{next}),T)$ which decides whether we should move to $s_{next}$ or stay at s. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to s_next. -At the same time we also keep a track of the best state $s_{best}$ across all iterations. Proceed till convergence or time runs out. +We start of with a random state $s$. In every step, we choose a neighbouring state $s_{next}$ of the current state $s$. If $E(s_{next}) < E(s)$, then we update $s = s_{next}$. Otherwise, we use a probability acceptance function $P(E(s),E(s_{next}),T)$ which decides whether we should move to $s_{next}$ or stay at $s$. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to $s_{next}$. +At the same time we also keep a track of the best state $s_{best}$ across all iterations. Proceeding till convergence or time runs out. +### How does this work? + +This algorithm is called simulated annealing because we are simulating the process of annealing, wherein a material is heated up and allowed to cool, in order to allow the atoms inside to rearrange themselves in an arrangement with minimal internal energy, which in turn causes the material to have different properties. The state is the arrangement of atoms and the internal energy is the function being minimised. We can think of the original state of the atoms, as a local minima for its internal energy. To make the material rearrange its atoms, we need to motivate it to go across a region where its internal energy is not minimised in order to reach the global minima. This motivation is given by heating the material to a higher temperature. + +Simulated annealing, literally simulates this process. We start off with some random state (material) and set a high temperature (heat it up). Now, the algorithm is ready to accept states which have a higher energy than the current state, as it is motivated by the high value of $T$. This prevents the algorithm from getting stuck inside local minimas and move towards the global minima. As time progresses, the algorithm cools down and refuses the states with higher energy and moves into the closest minima it has found. + + +
+ +
+A visual representation of simulated annealing, searching for the maxima of this function with multiple local maxima.. +
+This gif by [Kingpin13](https://commons.wikimedia.org/wiki/User:Kingpin13) is distributed under CC0 1.0 license. +
## Probability Acceptance Function -$$ -P(E,E_{next},T) = + +$P(E,E_{next},T) = \begin{cases} \text{True} &\quad\text{if } \exp{\frac{-(E_{next}-E)}{T}} \ge random(0,1) \\ \text{False} &\quad\text{otherwise}\\ - \end{cases} -$$ -This function takes in the current state, the next state and the Temperature , returning a boolean value, which tells our search whether it should move to $s_{next}$ or stay at s. Note that for $E_{next} < E$ , this function will always return True. + \end{cases}$ + +This function takes in the current state, the next state and the Temperature , returning a boolean value, which tells our search whether it should move to $s_{next}$ or stay at $s$. Note that for $E_{next} < E$ , this function will always return True. ```cpp bool P(double E,double E_next,double T){ @@ -99,13 +113,12 @@ pair simAnneal(){ Fill in the state class functions as appropriate. If you are trying to find a global maxima and not a minima, ensure that the $E()$ function returns negative of the function you are maximising and finally print out $-E_{best}$. Set the below parameters as per your need. ### Parameters -- T : Temperature. Set it to a higher value if you want the search to run for a longer time -- u : Decay. Decides the rate of cooling. A slower cooling rate (larger value of u) usually gives better results. Ensure $u < 1$. +- $T$ : Temperature. Set it to a higher value if you want the search to run for a longer time +- $u$ : Decay. Decides the rate of cooling. A slower cooling rate (larger value of u) usually gives better results. Ensure $u < 1$. The number of iterations the loop will run for is given by the expression -$$ -N = \lceil -\log_{u}{T} \rceil -$$ + +$N = \lceil -\log_{u}{T} \rceil$ To see the effect of decay rate on solution results, run simulated annealing for decay rates 0.95 , 0.97 and 0.99 and see the difference. From 1962436bf3f4c970a7d6c265263186afdf721e12 Mon Sep 17 00:00:00 2001 From: Prithvi-Rao Date: Tue, 29 Oct 2024 09:53:44 +0530 Subject: [PATCH 06/86] updated code --- src/num_methods/simulated_annealing.md | 96 +++++++++++++++++--------- 1 file changed, 62 insertions(+), 34 deletions(-) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index 1af1d49cd..0e650625d 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -7,7 +7,7 @@ tags: **Simulated Annealing (SA)** is a randomized algorithm, which approximates the global optimum of a function. It's called a randomized algorithm, because it employs a certain amount of randomness in its search and thus its output can vary for the same input. -## The Problem +## The problem We are given a function $E(s)$, which calculates the potential of the state $s$. We are tasked with finding the state $s_{best}$ at which $E(s)$ is minimized. **SA** is suited for problems where the states are discrete and $E(s)$ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). @@ -18,17 +18,17 @@ You are given a set of nodes in 2 dimensional space. Each node is characterised ### State State space is the collection of all possible values that can be taken by the independent variables. -A State is a unique point in the state space of the problem. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a State. +A state is a unique point in the state space of the problem. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a state. ### Neighbouring state It is a state in the state space which is close to the previous state. This usually means that we can obtain the neighbouring state from the original state using a simple transform. In the case of the Travelling Salesman Problem, a neighbouring state is obtained by randomly choosing 2 nodes, and swapping their positions in the current state. -### The Energy Function E(s) +### The energy function E(s) $E(s)$ is the function which needs to be minimised (or maximised). It maps every state to a real number. In the case of TSP, $E(s)$ returns the distance of travelling one full circle in the order of nodes in the state. -## The Approach +## The approach We start of with a random state $s$. In every step, we choose a neighbouring state $s_{next}$ of the current state $s$. If $E(s_{next}) < E(s)$, then we update $s = s_{next}$. Otherwise, we use a probability acceptance function $P(E(s),E(s_{next}),T)$ which decides whether we should move to $s_{next}$ or stay at $s$. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to $s_{next}$. At the same time we also keep a track of the best state $s_{best}$ across all iterations. Proceeding till convergence or time runs out. @@ -48,7 +48,7 @@ Simulated annealing, literally simulates this process. We start off with some ra This gif by [Kingpin13](https://commons.wikimedia.org/wiki/User:Kingpin13) is distributed under CC0 1.0 license. -## Probability Acceptance Function +## Probability Acceptance Function(PAF) $P(E,E_{next},T) = \begin{cases} @@ -60,9 +60,8 @@ This function takes in the current state, the next state and the Temperature , r ```cpp bool P(double E,double E_next,double T){ - double e = 2.71828; double prob = (double)rand()/RAND_MAX; // Generate a random number between 0 and 1 - if(pow(e,-(E_next-E)/T) > prob) return true; + if(exp(-(E_next-E)/T) > prob) return true; else return false; } ``` @@ -74,23 +73,28 @@ class state{ state(){ // Generate the initial state } + state(state& s){ + // Implement the copy constructor + } state next(){ - state next; - next = s; - // Make changes to the state "next" and then return it - return next; + state s_next = state(*this); + + // Modify s_next to the neighbouring state + + return s_next; } double E(){ - // implement the cost function here + // Implement the cost function here }; }; -pair simAnneal(){ +pair simAnneal(){ state s = state(); - state best = s; + state best = state(s); double T = 1000; // Initial temperature double u = 0.99; // decay rate - double E = s.E(),E_next; + double E = s.E(); + double E_next; double E_best = E; while (T > 1){ state next = s.next(); @@ -113,39 +117,42 @@ pair simAnneal(){ Fill in the state class functions as appropriate. If you are trying to find a global maxima and not a minima, ensure that the $E()$ function returns negative of the function you are maximising and finally print out $-E_{best}$. Set the below parameters as per your need. ### Parameters -- $T$ : Temperature. Set it to a higher value if you want the search to run for a longer time -- $u$ : Decay. Decides the rate of cooling. A slower cooling rate (larger value of u) usually gives better results. Ensure $u < 1$. +- $T$ : Temperature. Set it to a higher value if you want the search to run for a longer time. +- $u$ : Decay. Decides the rate of cooling. A slower cooling rate (larger value of u) usually gives better results, at the cost of running for a longer time. Ensure $u < 1$. The number of iterations the loop will run for is given by the expression $N = \lceil -\log_{u}{T} \rceil$ -To see the effect of decay rate on solution results, run simulated annealing for decay rates 0.95 , 0.97 and 0.99 and see the difference. +Tips for choosing $T$ and $u$ : If there are many local minimas and a wide state space, set $u = 0.999$, for a slow cooling rate, which will allow the algorithm to explore more possibilities. On the other hand, if the state space is narrower, $u = 0.99$ should suffice. If you are not sure, play it safe by setting $u = 0.998$ or higher. Calculate the time complexity of a single iteration of the algorithm, and use this to approximate a value of $N$ which will prevent TLE, then use the below formula to obtain $T$. + +$T = u^{-N}$ -### Example State class for TSP +### Example implementation for TSP ```cpp + class state{ public: vector> points; - state(){ // Initial random order of points - points = {}; // Fill in some points to start with, or generate them randomly + state(){ + points = { {0,0},{2,2},{0,2},{2,0},{0,1},{1,2},{2,1},{1,0} }; + } + state(state& s){ + points = s.points; } - state next(){ // picks 2 random indices and swaps them - state s_next; - s_next.points = points; - int a = ((rand()*points.size())/RAND_MAX); - int b = ((rand()*points.size())/RAND_MAX); - pair t = s_next.points[a]; - s_next.points[a] = s_next.points[b]; - s_next.points[b] = t; + state next(){ + state s_next = state(*this); + int a = (rand()%points.size()); + int b = (rand()%points.size()); + s_next.points[a].swap(s_next.points[b]); return s_next; } - double euclidean(pair a, pair b){ // return euclidean distance between 2 points + double euclidean(pair a, pair b){ return pow(pow((a.first-b.first),2)+pow((a.second-b.second),2),0.5); } - double E(){ // calculates the round cost of travelling one full circle. + double E(){ double dist = 0; bool first = true; int n = points.size(); @@ -155,13 +162,34 @@ class state{ return dist; }; }; + + +int main(){ + pair res; + res = simAnneal(); + double E_best = res.first; + state best = res.second; + cout << "Lenght of shortest path found : " << E_best << "\n"; + cout << "Order of points in shortest path : \n"; + for(auto x: best.points){ + cout << x.first << " " << x.second << "\n"; + } +} ``` -## Extra Modifications to the Algorithm: +## Further modifications to the algorithm: - Add a time based exit condition to the while loop to prevent TLE -- You can replace the e value in the Probability Acceptance function to any real number > 1. For a given $E_{next} - E > 0$, a higher e value reduces the chance of accepting that state and a smaller e value, increases it. - +- The Probability acceptance function given above, prefers accepting states which are lower in energy because of the $E_{next} - E$ factor in the numerator of the exponent. You can simply remove this factor, to make the PAF independent of the difference in energies. +- The effect of the difference in energies, $E_{next} - E$ on the PAF can be increased/decreased by increasing/decreasing the base of the exponent as shown below: +```cpp +bool P(double E,double E_next,double T){ + double e = 2; // set e to any real number greater than 1 + double prob = (double)rand()/RAND_MAX; // Generate a random number between 0 and 1 + if(pow(e,-(E_next-E)/T) > prob) return true; + else return false; +} +``` ## Problems From 7b46a269250c13aa7ae3c63a2c75d1e984ffa871 Mon Sep 17 00:00:00 2001 From: Prithvi-Rao Date: Tue, 29 Oct 2024 10:38:33 +0530 Subject: [PATCH 07/86] fixed braces error --- src/num_methods/simulated_annealing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index 0e650625d..5c06de057 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -136,7 +136,7 @@ class state{ vector> points; state(){ - points = { {0,0},{2,2},{0,2},{2,0},{0,1},{1,2},{2,1},{1,0} }; + {% raw %}points = {{0,0},{2,2},{0,2},{2,0},{0,1},{1,2},{2,1},{1,0}};{% endraw %} } state(state& s){ points = s.points; @@ -181,7 +181,7 @@ int main(){ - Add a time based exit condition to the while loop to prevent TLE - The Probability acceptance function given above, prefers accepting states which are lower in energy because of the $E_{next} - E$ factor in the numerator of the exponent. You can simply remove this factor, to make the PAF independent of the difference in energies. -- The effect of the difference in energies, $E_{next} - E$ on the PAF can be increased/decreased by increasing/decreasing the base of the exponent as shown below: +- The effect of the difference in energies, $E_{next} - E$, on the PAF can be increased/decreased by increasing/decreasing the base of the exponent as shown below: ```cpp bool P(double E,double E_next,double T){ double e = 2; // set e to any real number greater than 1 From bab84cda941be4061f3d139252b8cdc370ed6002 Mon Sep 17 00:00:00 2001 From: Prithvi-Rao Date: Tue, 5 Nov 2024 09:16:10 +0530 Subject: [PATCH 08/86] fixes --- src/num_methods/simulated_annealing.md | 150 +++++++++++++------------ 1 file changed, 78 insertions(+), 72 deletions(-) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index 5c06de057..abd035950 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -9,35 +9,33 @@ tags: ## The problem -We are given a function $E(s)$, which calculates the potential of the state $s$. We are tasked with finding the state $s_{best}$ at which $E(s)$ is minimized. **SA** is suited for problems where the states are discrete and $E(s)$ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). +We are given a function $E(s)$, which calculates the energy of the state $s$. We are tasked with finding the state $s_{best}$ at which $E(s)$ is minimized. **SA** is suited for problems where the states are discrete and $E(s)$ has multiple local minima. We'll take the example of the [Travelling Salesman Problem (TSP)](https://en.wikipedia.org/wiki/Travelling_salesman_problem). ### Travelling Salesman Problem (TSP) -You are given a set of nodes in 2 dimensional space. Each node is characterised by its $x$ and $y$ coordinates. Your task is to find the an ordering of the nodes, which will minimise the distance to be travelled when visiting these nodes in that order. +You are given a set of nodes in 2 dimensional space. Each node is characterised by its $x$ and $y$ coordinates. Your task is to find an ordering of the nodes, which will minimise the distance to be travelled when visiting these nodes in that order. -### State - -State space is the collection of all possible values that can be taken by the independent variables. -A state is a unique point in the state space of the problem. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a state. - -### Neighbouring state +## Motivation +Annealing is a metallurgical process , wherein a material is heated up and allowed to cool, in order to allow the atoms inside to rearrange themselves in an arrangement with minimal internal energy, which in turn causes the material to have different properties. The state is the arrangement of atoms and the internal energy is the function being minimised. We can think of the original state of the atoms, as a local minima for its internal energy. To make the material rearrange its atoms, we need to motivate it to go across a region where its internal energy is not minimised in order to reach the global minima. This motivation is given by heating the material to a higher temperature. -It is a state in the state space which is close to the previous state. This usually means that we can obtain the neighbouring state from the original state using a simple transform. In the case of the Travelling Salesman Problem, a neighbouring state is obtained by randomly choosing 2 nodes, and swapping their positions in the current state. +Simulated annealing, literally, simulates this process. We start off with some random state (material) and set a high temperature (heat it up). Now, the algorithm is ready to accept states which have a higher energy than the current state, as it is motivated by the high temperature. This prevents the algorithm from getting stuck inside local minimas and move towards the global minima. As time progresses, the algorithm cools down and refuses the states with higher energy and moves into the closest minima it has found. ### The energy function E(s) $E(s)$ is the function which needs to be minimised (or maximised). It maps every state to a real number. In the case of TSP, $E(s)$ returns the distance of travelling one full circle in the order of nodes in the state. -## The approach +### State + +The state space is the domain of the energy function, E(s), and a state is any element which belongs to the state space. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a state. -We start of with a random state $s$. In every step, we choose a neighbouring state $s_{next}$ of the current state $s$. If $E(s_{next}) < E(s)$, then we update $s = s_{next}$. Otherwise, we use a probability acceptance function $P(E(s),E(s_{next}),T)$ which decides whether we should move to $s_{next}$ or stay at $s$. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to $s_{next}$. -At the same time we also keep a track of the best state $s_{best}$ across all iterations. Proceeding till convergence or time runs out. +### Neighbouring state -### How does this work? +It is a state in the state space which is close to the previous state. This usually means that we can obtain the neighbouring state from the original state using a simple transform. In the case of the Travelling Salesman Problem, a neighbouring state is obtained by randomly choosing 2 nodes, and swapping their positions in the current state. -This algorithm is called simulated annealing because we are simulating the process of annealing, wherein a material is heated up and allowed to cool, in order to allow the atoms inside to rearrange themselves in an arrangement with minimal internal energy, which in turn causes the material to have different properties. The state is the arrangement of atoms and the internal energy is the function being minimised. We can think of the original state of the atoms, as a local minima for its internal energy. To make the material rearrange its atoms, we need to motivate it to go across a region where its internal energy is not minimised in order to reach the global minima. This motivation is given by heating the material to a higher temperature. +## Algorithm -Simulated annealing, literally simulates this process. We start off with some random state (material) and set a high temperature (heat it up). Now, the algorithm is ready to accept states which have a higher energy than the current state, as it is motivated by the high value of $T$. This prevents the algorithm from getting stuck inside local minimas and move towards the global minima. As time progresses, the algorithm cools down and refuses the states with higher energy and moves into the closest minima it has found. +We start with a random state $s$. In every step, we choose a neighbouring state $s_{next}$ of the current state $s$. If $E(s_{next}) < E(s)$, then we update $s = s_{next}$. Otherwise, we use a probability acceptance function $P(E(s),E(s_{next}),T)$ which decides whether we should move to $s_{next}$ or stay at $s$. T here is the temperature, which is initially set to a high value and decays slowly with every step. The higher the temperature, the more likely it is to move to $s_{next}$. +At the same time we also keep a track of the best state $s_{best}$ across all iterations. Proceeding till convergence or time runs out.
@@ -45,63 +43,66 @@ Simulated annealing, literally simulates this process. We start off with some ra
A visual representation of simulated annealing, searching for the maxima of this function with multiple local maxima..
-This gif by [Kingpin13](https://commons.wikimedia.org/wiki/User:Kingpin13) is distributed under CC0 1.0 license. -
+This animation by [Kingpin13](https://commons.wikimedia.org/wiki/User:Kingpin13) is distributed under CC0 1.0 license. + +### Temperature($T$) and decay($u$) + +The temperature of the system quantifies the willingness of the algorithm to accept a state with a higher energy. The decay is a constant which quantifies the "cooling rate" of the algorithm. A slow cooling rate (larger $u$) is known to give better results. ## Probability Acceptance Function(PAF) $P(E,E_{next},T) = \begin{cases} - \text{True} &\quad\text{if } \exp{\frac{-(E_{next}-E)}{T}} \ge random(0,1) \\ + \text{True} &\quad\text{if } \mathcal{U}_{[0,1]} \le \exp(-\frac{E_{next}-E}{T}) \\ \text{False} &\quad\text{otherwise}\\ \end{cases}$ -This function takes in the current state, the next state and the Temperature , returning a boolean value, which tells our search whether it should move to $s_{next}$ or stay at $s$. Note that for $E_{next} < E$ , this function will always return True. +Here, $\mathcal{U}_{[0,1]}$ is a continuous uniform random value on $[0,1]$. This function takes in the current state, the next state and the temperature, returning a boolean value, which tells our search whether it should move to $s_{next}$ or stay at $s$. Note that for $E_{next} < E$ , this function will always return True, otherwise it can still make the move with probability $\exp(-\frac{E_{next}-E}{T})$, which corresponds to the [Gibbs measure](https://en.wikipedia.org/wiki/Gibbs_measure). ```cpp -bool P(double E,double E_next,double T){ - double prob = (double)rand()/RAND_MAX; // Generate a random number between 0 and 1 - if(exp(-(E_next-E)/T) > prob) return true; - else return false; +bool P(double E,double E_next,double T,mt19937 rng){ + double prob = exp(-(E_next-E)/T); + if(prob > 1) return true; + else{ + bernoulli_distribution d(prob); + return d(rng); + } } ``` ## Code Template ```cpp -class state{ +class state { public: - state(){ + state() { // Generate the initial state } - state(state& s){ - // Implement the copy constructor - } - state next(){ - state s_next = state(*this); - - // Modify s_next to the neighbouring state - + state next() { + state s_next; + // Modify s_next to a random neighboring state return s_next; } - double E(){ - // Implement the cost function here + double E() { + // Implement the energy function here }; }; -pair simAnneal(){ + +pair simAnneal() { state s = state(); - state best = state(s); - double T = 1000; // Initial temperature - double u = 0.99; // decay rate + state best = s; + double T = 10000; // Initial temperature + double u = 0.995; // decay rate double E = s.E(); double E_next; double E_best = E; - while (T > 1){ + mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); + while (T > 1) { state next = s.next(); E_next = next.E(); - if(P(E,E_next,T)){ + if (P(E, E_next, T, rng)) { s = next; - if(E_next < E_best){ + if (E_next < E_best) { best = s; E_best = E_next; } @@ -109,15 +110,15 @@ pair simAnneal(){ E = E_next; T *= u; } - return {E_best,best}; + return {E_best, best}; } ``` ## How to use: -Fill in the state class functions as appropriate. If you are trying to find a global maxima and not a minima, ensure that the $E()$ function returns negative of the function you are maximising and finally print out $-E_{best}$. Set the below parameters as per your need. +Fill in the state class functions as appropriate. If you are trying to find a global maxima and not a minima, ensure that the $E()$ function returns negative of the function you are maximizing and print $-E_{best}$ in the end. Set the below parameters as per your need. ### Parameters -- $T$ : Temperature. Set it to a higher value if you want the search to run for a longer time. +- $T$ : Initial temperature. Set it to a higher value if you want the search to run for a longer time. - $u$ : Decay. Decides the rate of cooling. A slower cooling rate (larger value of u) usually gives better results, at the cost of running for a longer time. Ensure $u < 1$. The number of iterations the loop will run for is given by the expression @@ -131,47 +132,47 @@ $T = u^{-N}$ ### Example implementation for TSP ```cpp -class state{ +class state { public: - vector> points; - - state(){ - {% raw %}points = {{0,0},{2,2},{0,2},{2,0},{0,1},{1,2},{2,1},{1,0}};{% endraw %} - } - state(state& s){ - points = s.points; + vector> points; + std::mt19937 mt{ static_cast( + std::chrono::steady_clock::now().time_since_epoch().count() + ) }; + state() { + points = {%raw%} {{0,0},{2,2},{0,2},{2,0},{0,1},{1,2},{2,1},{1,0}} {%endraw%}; } - state next(){ - state s_next = state(*this); - int a = (rand()%points.size()); - int b = (rand()%points.size()); + state next() { + state s_next; + s_next.points = points; + uniform_int_distribution<> choose(0, points.size()-1); + int a = choose(mt); + int b = choose(mt); s_next.points[a].swap(s_next.points[b]); return s_next; } - double euclidean(pair a, pair b){ - return pow(pow((a.first-b.first),2)+pow((a.second-b.second),2),0.5); + double euclidean(pair a, pair b) { + return hypot(a.first - b.first, a.second - b.second); } - double E(){ + + double E() { double dist = 0; bool first = true; int n = points.size(); - for(int i = 0;i < n; i++){ - dist += euclidean(points[i],points[(i+1)%n]); - } + for (int i = 0;i < n; i++) + dist += euclidean(points[i], points[(i+1)%n]); return dist; }; }; - -int main(){ - pair res; +int main() { + pair res; res = simAnneal(); double E_best = res.first; state best = res.second; cout << "Lenght of shortest path found : " << E_best << "\n"; cout << "Order of points in shortest path : \n"; - for(auto x: best.points){ + for(auto x: best.points) { cout << x.first << " " << x.second << "\n"; } } @@ -180,14 +181,19 @@ int main(){ ## Further modifications to the algorithm: - Add a time based exit condition to the while loop to prevent TLE +- The decay implemented above is an exponential decay. You can always replace this with a decay function as per your needs. - The Probability acceptance function given above, prefers accepting states which are lower in energy because of the $E_{next} - E$ factor in the numerator of the exponent. You can simply remove this factor, to make the PAF independent of the difference in energies. - The effect of the difference in energies, $E_{next} - E$, on the PAF can be increased/decreased by increasing/decreasing the base of the exponent as shown below: ```cpp -bool P(double E,double E_next,double T){ - double e = 2; // set e to any real number greater than 1 - double prob = (double)rand()/RAND_MAX; // Generate a random number between 0 and 1 - if(pow(e,-(E_next-E)/T) > prob) return true; - else return false; +bool P(double E, double E_next, double T, mt19937 rng) { + e = 2 // set e to any real number greater than 1 + double prob = exp(-(E_next-E)/T); + if (prob > 1) + return true; + else { + bernoulli_distribution d(prob); + return d(rng); + } } ``` From 670cbaa2c8cfd742993a43542258f8ebd6a320c8 Mon Sep 17 00:00:00 2001 From: Mirco Paul <63196848+Electron1997@users.noreply.github.com> Date: Thu, 6 Feb 2025 22:26:53 +0100 Subject: [PATCH 09/86] Add practice problems Add some Burnside lemma practice problems sorted by difficulty --- src/combinatorics/burnside.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/combinatorics/burnside.md b/src/combinatorics/burnside.md index fa799399c..894b1e87d 100644 --- a/src/combinatorics/burnside.md +++ b/src/combinatorics/burnside.md @@ -266,3 +266,8 @@ int solve(int n, int m) { return sum / s.size(); } ``` +## Practice Problems +* [CSES - Counting Necklaces](https://cses.fi/problemset/task/2209) +* [CSES - Counting Grids](https://cses.fi/problemset/task/2210) +* [Codeforces - Buildings](https://codeforces.com/gym/101873/problem/B) +* [CS Academy - Cube Coloring](https://csacademy.com/contest/beta-round-8/task/cube-coloring/) From dc29826f28c7960efd657816a6dd4af22caf0ac7 Mon Sep 17 00:00:00 2001 From: CDTheGod <158807586+CDTheGod@users.noreply.github.com> Date: Wed, 5 Mar 2025 18:39:38 +0530 Subject: [PATCH 10/86] Update divide-and-conquer-dp.md --- src/dynamic_programming/divide-and-conquer-dp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynamic_programming/divide-and-conquer-dp.md b/src/dynamic_programming/divide-and-conquer-dp.md index 457e17c24..a33cc7b45 100644 --- a/src/dynamic_programming/divide-and-conquer-dp.md +++ b/src/dynamic_programming/divide-and-conquer-dp.md @@ -113,7 +113,7 @@ both! - [SPOJ - LARMY](https://www.spoj.com/problems/LARMY/) - [SPOJ - NKLEAVES](https://www.spoj.com/problems/NKLEAVES/) - [Timus - Bicolored Horses](https://acm.timus.ru/problem.aspx?space=1&num=1167) -- [USACO - Circular Barn](http://www.usaco.org/index.php?page=viewproblem2&cpid=616) +- [USACO - Circular Barn](https://usaco.org/index.php?page=viewproblem2&cpid=626) - [UVA - Arranging Heaps](https://onlinejudge.org/external/125/12524.pdf) - [UVA - Naming Babies](https://onlinejudge.org/external/125/12594.pdf) From b861d1ec80d7e08ff7ebfc71c8cf262db65cf346 Mon Sep 17 00:00:00 2001 From: Franklin Date: Sat, 8 Mar 2025 02:54:08 -0500 Subject: [PATCH 11/86] Update topological-sort.md In the implementation example, the if statement within the dfs function is missing a pair of brackets. --- src/graph/topological-sort.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graph/topological-sort.md b/src/graph/topological-sort.md index f8e8e9218..acfad5331 100644 --- a/src/graph/topological-sort.md +++ b/src/graph/topological-sort.md @@ -65,8 +65,9 @@ vector ans; void dfs(int v) { visited[v] = true; for (int u : adj[v]) { - if (!visited[u]) + if (!visited[u]) { dfs(u); + } } ans.push_back(v); } From 2c8dc7b96a5bd484eaa1715656ef6d474abf352c Mon Sep 17 00:00:00 2001 From: Jakob Kogler Date: Sun, 9 Mar 2025 13:30:00 +0100 Subject: [PATCH 12/86] Remove deprecated tags plugin flag --- mkdocs.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index ed15e7068..60f512bc6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -61,8 +61,7 @@ plugins: hooks: on_env: "hooks:on_env" - search - - tags: - tags_file: tags.md + - tags - literate-nav: nav_file: navigation.md - git-revision-date-localized: From bbe3477bc857e34ad82dad40a8442da3a7204ab7 Mon Sep 17 00:00:00 2001 From: Jakob Kogler Date: Sun, 9 Mar 2025 13:43:34 +0100 Subject: [PATCH 13/86] Make tags index work again --- src/tags.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tags.md b/src/tags.md index c462960cd..6759f272e 100644 --- a/src/tags.md +++ b/src/tags.md @@ -2,4 +2,4 @@ This file contains a global index of all tags used on the pages. -[TAGS] \ No newline at end of file + From 42952998071723361d0ec88314183af6f35f2fd6 Mon Sep 17 00:00:00 2001 From: "Yurii A." Date: Mon, 24 Mar 2025 21:49:18 +0200 Subject: [PATCH 14/86] Manacher's algorithm testcases (#1393) * Fix inconsistencies in Manacher's algorithm * Add test for manacher_odd * Update test_manacher_odd.cpp * empty commit to run tests? --------- Co-authored-by: Yurii A. Co-authored-by: Oleksandr Kulkov --- src/string/manacher.md | 8 ++--- test/test_manacher_odd.cpp | 74 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 test/test_manacher_odd.cpp diff --git a/src/string/manacher.md b/src/string/manacher.md index 2c7cb35b6..0c8bd5928 100644 --- a/src/string/manacher.md +++ b/src/string/manacher.md @@ -49,7 +49,7 @@ Such an algorithm is slow, it can calculate the answer only in $O(n^2)$. The implementation of the trivial algorithm is: ```cpp -vector manacher_odd(string s) { +vector manacher_odd_trivial(string s) { int n = s.size(); s = "$" + s + "^"; vector p(n + 2); @@ -68,7 +68,7 @@ Terminal characters `$` and `^` were used to avoid dealing with ends of the stri We describe the algorithm to find all the sub-palindromes with odd length, i. e. to calculate $d_{odd}[]$. -For fast calculation we'll maintain the **borders $(l, r)$** of the rightmost found (sub-)palindrome (i. e. the current rightmost (sub-)palindrome is $s[l+1] s[l+2] \dots s[r-1]$). Initially we set $l = 0, r = 1$, which corresponds to the empty string. +For fast calculation we'll maintain the **exclusive borders $(l, r)$** of the rightmost found (sub-)palindrome (i. e. the current rightmost (sub-)palindrome is $s[l+1] s[l+2] \dots s[r-1]$). Initially we set $l = 0, r = 1$, which corresponds to the empty string. So, we want to calculate $d_{odd}[i]$ for the next $i$, and all the previous values in $d_{odd}[]$ have been already calculated. We do the following: @@ -140,12 +140,12 @@ For calculating $d_{odd}[]$, we get the following code. Things to note: - The while loop denotes the trivial algorithm. We launch it irrespective of the value of $k$. - If the size of palindrome centered at $i$ is $x$, then $d_{odd}[i]$ stores $\frac{x+1}{2}$. -```cpp +```{.cpp file=manacher_odd} vector manacher_odd(string s) { int n = s.size(); s = "$" + s + "^"; vector p(n + 2); - int l = 1, r = 1; + int l = 0, r = 1; for(int i = 1; i <= n; i++) { p[i] = max(0, min(r - i, p[l + (r - i)])); while(s[i - p[i]] == s[i + p[i]]) { diff --git a/test/test_manacher_odd.cpp b/test/test_manacher_odd.cpp new file mode 100644 index 000000000..cd46b7488 --- /dev/null +++ b/test/test_manacher_odd.cpp @@ -0,0 +1,74 @@ +#include +using namespace std; + +#include "manacher_odd.h" + +string getRandomString(size_t n, uint32_t seed, char minLetter='a', char maxLetter='b') { + assert(minLetter <= maxLetter); + const size_t nLetters = static_cast(maxLetter) - static_cast(minLetter) + 1; + std::uniform_int_distribution distr(0, nLetters - 1); + std::mt19937 gen(seed); + + string res; + res.reserve(n); + + for (size_t i = 0; i < n; ++i) + res.push_back('a' + distr(gen)); + + return res; +} + +bool testManacherOdd(const std::string &s) { + const auto n = s.size(); + const auto d_odd = manacher_odd(s); + + if (d_odd.size() != n) + return false; + + const auto inRange = [&](size_t idx) { + return idx >= 0 && idx < n; + }; + + for (size_t i = 0; i < n; ++i) { + if (d_odd[i] < 0) + return false; + for (int d = 0; d < d_odd[i]; ++d) { + const auto idx1 = i - d; + const auto idx2 = i + d; + + if (!inRange(idx1) || !inRange(idx2)) + return false; + if (s[idx1] != s[idx2]) + return false; + } + + const auto idx1 = i - d_odd[i]; + const auto idx2 = i + d_odd[i]; + if (inRange(idx1) && inRange(idx2) && s[idx1] == s[idx2]) + return false; + } + + return true; +} + +int main() { + vector testCases; + + testCases.push_back(""); + for (size_t i = 1; i <= 25; ++i) { + auto s = string{}; + s.resize(i, 'a'); + testCases.push_back(move(s)); + } + testCases.push_back("abba"); + testCases.push_back("abccbaasd"); + for (size_t n = 9; n <= 100; n += 10) + testCases.push_back(getRandomString(n, /* seed */ n, 'a', 'd')); + for (size_t n = 7; n <= 100; n += 10) + testCases.push_back(getRandomString(n, /* seed */ n)); + + for (const auto &s: testCases) + assert(testManacherOdd(s)); + + return 0; +} From 82a06ff7246bc161dfc6a176f2adf79dba19f72b Mon Sep 17 00:00:00 2001 From: Yury Semenov Date: Mon, 24 Mar 2025 23:15:38 +0300 Subject: [PATCH 15/86] Added a paragraph on golden section search (#1119) * . * Update ternary_search.md --------- Co-authored-by: Oleksandr Kulkov --- src/num_methods/ternary_search.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/num_methods/ternary_search.md b/src/num_methods/ternary_search.md index 59afaaa82..7e73c7771 100644 --- a/src/num_methods/ternary_search.md +++ b/src/num_methods/ternary_search.md @@ -57,6 +57,20 @@ If $f(x)$ takes integer parameter, the interval $[l, r]$ becomes discrete. Since The difference occurs in the stopping criterion of the algorithm. Ternary search will have to stop when $(r - l) < 3$, because in that case we can no longer select $m_1$ and $m_2$ to be different from each other as well as from $l$ and $r$, and this can cause an infinite loop. Once $(r - l) < 3$, the remaining pool of candidate points $(l, l + 1, \ldots, r)$ needs to be checked to find the point which produces the maximum value $f(x)$. +### Golden section search + +In some cases computing $f(x)$ may be quite slow, but reducing the number of iterations is infeasible due to precision issues. Fortunately, it is possible to compute $f(x)$ only once at each iteration (except the first one). + +To see how to do this, let's revisit the selection method for $m_1$ and $m_2$. Suppose that we select $m_1$ and $m_2$ on $[l, r]$ in such a way that $\frac{r - l}{r - m_1} = \frac{r - l}{m_2 - l} = \varphi$ where $\varphi$ is some constant. In order to reduce the amount of computations, we want to select such $\varphi$ that on the next iteration one of the new evaluation points $m_1'$, $m_2'$ will coincide with either $m_1$ or $m_2$, so that we can reuse the already computed function value. + +Now suppose that after the current iteration we set $l = m_1$. Then the point $m_1'$ will satisfy $\frac{r - m_1}{r - m_1'} = \varphi$. We want this point to coincide with $m_2$, meaning that $\frac{r - m_1}{r - m_2} = \varphi$. + +Multiplying both sides of $\frac{r - m_1}{r - m_2} = \varphi$ by $\frac{r - m_2}{r - l}$ we obtain $\frac{r - m_1}{r - l} = \varphi\frac{r - m_2}{r - l}$. Note that $\frac{r - m_1}{r - l} = \frac{1}{\varphi}$ and $\frac{r - m_2}{r - l} = \frac{r - l + l - m_2}{r - l} = 1 - \frac{1}{\varphi}$. Substituting that and multiplying by $\varphi$, we obtain the following equation: + +$\varphi^2 - \varphi - 1 = 0$ + +This is a well-known golden section equation. Solving it yields $\frac{1 \pm \sqrt{5}}{2}$. Since $\varphi$ must be positive, we obtain $\varphi = \frac{1 + \sqrt{5}}{2}$. By applying the same logic to the case when we set $r = m_2$ and want $m_2'$ to coincide with $m_1$, we obtain the same value of $\varphi$ as well. So, if we choose $m_1 = l + \frac{r - l}{1 + \varphi}$ and $m_2 = r - \frac{r - l}{1 + \varphi}$, on each iteration we can re-use one of the values $f(x)$ computed on the previous iteration. + ## Implementation ```cpp @@ -81,6 +95,7 @@ Here `eps` is in fact the absolute error (not taking into account errors due to Instead of the criterion `r - l > eps`, we can select a constant number of iterations as a stopping criterion. The number of iterations should be chosen to ensure the required accuracy. Typically, in most programming challenges the error limit is ${10}^{-6}$ and thus 200 - 300 iterations are sufficient. Also, the number of iterations doesn't depend on the values of $l$ and $r$, so the number of iterations corresponds to the required relative error. ## Practice Problems + - [Codeforces - New Bakery](https://codeforces.com/problemset/problem/1978/B) - [Codechef - Race time](https://www.codechef.com/problems/AMCS03) - [Hackerearth - Rescuer](https://www.hackerearth.com/problem/algorithm/rescuer-2d2495cb/) @@ -95,5 +110,8 @@ Instead of the criterion `r - l > eps`, we can select a constant number of itera * [Codeforces - Devu and his Brother](https://codeforces.com/problemset/problem/439/D) * [Codechef - Is This JEE ](https://www.codechef.com/problems/ICM2003) * [Codeforces - Restorer Distance](https://codeforces.com/contest/1355/problem/E) +* [TIMUS 1058 Chocolate](https://acm.timus.ru/problem.aspx?space=1&num=1058) +* [TIMUS 1436 Billboard](https://acm.timus.ru/problem.aspx?space=1&num=1436) +* [TIMUS 1451 Beerhouse Tale](https://acm.timus.ru/problem.aspx?space=1&num=1451) * [TIMUS 1719 Kill the Shaitan-Boss](https://acm.timus.ru/problem.aspx?space=1&num=1719) * [TIMUS 1913 Titan Ruins: Alignment of Forces](https://acm.timus.ru/problem.aspx?space=1&num=1913) From 7c1254ba49761d3eaedb7e7387c3489a1e5647de Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Mon, 24 Mar 2025 21:26:18 +0100 Subject: [PATCH 16/86] Empty commit for GitHub Actions --- src/num_methods/simulated_annealing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index abd035950..a5f6b466a 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -201,4 +201,4 @@ bool P(double E, double E_next, double T, mt19937 rng) { - [USACO Jan 2017 - Subsequence Reversal](https://usaco.org/index.php?page=viewproblem2&cpid=698) - [Deltix Summer 2021 - DIY Tree](https://codeforces.com/contest/1556/problem/H) -- [AtCoder Contest Scheduling](https://atcoder.jp/contests/intro-heuristics/tasks/intro_heuristics_a) \ No newline at end of file +- [AtCoder Contest Scheduling](https://atcoder.jp/contests/intro-heuristics/tasks/intro_heuristics_a) From 9b8c5b638057a351ed79439d9ebd73002190fd81 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Mon, 24 Mar 2025 21:33:53 +0100 Subject: [PATCH 17/86] Close
tag --- src/num_methods/simulated_annealing.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index a5f6b466a..f9bd1686d 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -44,6 +44,7 @@ At the same time we also keep a track of the best state $s_{best}$ across all it A visual representation of simulated annealing, searching for the maxima of this function with multiple local maxima..
This animation by [Kingpin13](https://commons.wikimedia.org/wiki/User:Kingpin13) is distributed under CC0 1.0 license. +
### Temperature($T$) and decay($u$) From e24c67450d38ffdde84b1191a85f9c4b1687d054 Mon Sep 17 00:00:00 2001 From: FloppaInspector <136809316+FloppaInspector@users.noreply.github.com> Date: Sun, 6 Apr 2025 00:39:54 +0900 Subject: [PATCH 18/86] Update knuth-optimization.md In time complexity proof cancellation explanation, j=N -> j=N-1 --- src/dynamic_programming/knuth-optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynamic_programming/knuth-optimization.md b/src/dynamic_programming/knuth-optimization.md index 535c7caf2..35978b839 100644 --- a/src/dynamic_programming/knuth-optimization.md +++ b/src/dynamic_programming/knuth-optimization.md @@ -77,7 +77,7 @@ $$ \sum\limits_{i=1}^N \sum\limits_{j=i}^{N-1} [opt(i+1,j+1)-opt(i,j)]. $$ -As you see, most of the terms in this expression cancel each other out, except for positive terms with $j=N$ and negative terms with $i=1$. Thus, the whole sum can be estimated as +As you see, most of the terms in this expression cancel each other out, except for positive terms with $j=N-1$ and negative terms with $i=1$. Thus, the whole sum can be estimated as $$ \sum\limits_{k=1}^N[opt(k,N)-opt(1,k)] = O(n^2), From 1e3a93051eb22ad0238d3265246b650ce8a8954b Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Tue, 8 Apr 2025 11:45:34 +0200 Subject: [PATCH 19/86] Remove navigation tabs, add toggle to hide sidebar (#1440) --- .github/workflows/build.yml | 2 +- mkdocs.yml | 3 ++- scripts/install-mkdocs.sh | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e820830eb..37a634b16 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5.2.0 with: - python-version: '3.8' + python-version: '3.11' - name: Install mkdocs-material run: | scripts/install-mkdocs.sh diff --git a/mkdocs.yml b/mkdocs.yml index 60f512bc6..466463564 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,7 +22,6 @@ theme: icon: repo: fontawesome/brands/github features: - - navigation.tabs - toc.integrate - search.suggest - content.code.copy @@ -57,6 +56,8 @@ markdown_extensions: permalink: true plugins: + - toggle-sidebar: + toggle_button: all - mkdocs-simple-hooks: hooks: on_env: "hooks:on_env" diff --git a/scripts/install-mkdocs.sh b/scripts/install-mkdocs.sh index 4202c9a97..9c4e73c3f 100755 --- a/scripts/install-mkdocs.sh +++ b/scripts/install-mkdocs.sh @@ -2,6 +2,7 @@ pip install \ "mkdocs-material>=9.0.2" \ + mkdocs-toggle-sidebar-plugin \ mkdocs-macros-plugin \ mkdocs-literate-nav \ mkdocs-git-authors-plugin \ From 21299e74b39389acb6bf8ad257d65cc1875ffa93 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Mon, 14 Apr 2025 22:32:08 -0400 Subject: [PATCH 20/86] add_script updates? --- src/algebra/factorization.md | 4 +++- src/algebra/sieve-of-eratosthenes.md | 4 +++- src/data_structures/fenwick.md | 4 +++- src/geometry/basic-geometry.md | 16 ++++++++++++---- src/geometry/convex_hull_trick.md | 8 ++++++-- src/geometry/delaunay.md | 4 +++- src/geometry/intersecting_segments.md | 12 +++++++++--- src/geometry/lattice-points.md | 8 ++++++-- src/geometry/manhattan-distance.md | 8 ++++++-- src/geometry/minkowski.md | 4 +++- src/geometry/planar.md | 8 ++++++-- src/geometry/point-location.md | 8 ++++++-- src/geometry/tangents-to-two-circles.md | 4 +++- src/geometry/vertical_decomposition.md | 4 +++- src/graph/2SAT.md | 8 ++++++-- src/graph/edmonds_karp.md | 16 ++++++++++++---- src/graph/hld.md | 4 +++- src/graph/lca.md | 4 +++- src/graph/lca_farachcoltonbender.md | 4 +++- src/graph/rmq_linear.md | 8 ++++++-- src/graph/topological-sort.md | 6 +++--- src/others/stern_brocot_tree_farey_sequences.md | 4 +++- src/others/tortoise_and_hare.md | 12 +++++++++--- 23 files changed, 120 insertions(+), 42 deletions(-) diff --git a/src/algebra/factorization.md b/src/algebra/factorization.md index 58a43b961..11bf4049c 100644 --- a/src/algebra/factorization.md +++ b/src/algebra/factorization.md @@ -246,7 +246,9 @@ If $p$ is smaller than $\sqrt{n}$, the repetition will likely start in $O(\sqrt[ Here is a visualization of such a sequence $\{x_i \bmod p\}$ with $n = 2206637$, $p = 317$, $x_0 = 2$ and $f(x) = x^2 + 1$. From the form of the sequence you can see very clearly why the algorithm is called Pollard's $\rho$ algorithm. -
![Pollard's rho visualization](pollard_rho.png)
+
+ Pollard's rho visualization +
Yet, there is still an open question. How can we exploit the properties of the sequence $\{x_i \bmod p\}$ to our advantage without even knowing the number $p$ itself? diff --git a/src/algebra/sieve-of-eratosthenes.md b/src/algebra/sieve-of-eratosthenes.md index a07e6dc02..560d176e7 100644 --- a/src/algebra/sieve-of-eratosthenes.md +++ b/src/algebra/sieve-of-eratosthenes.md @@ -19,7 +19,9 @@ And we continue this procedure until we have processed all numbers in the row. In the following image you can see a visualization of the algorithm for computing all prime numbers in the range $[1; 16]$. It can be seen, that quite often we mark numbers as composite multiple times. -
![Sieve of Eratosthenes](sieve_eratosthenes.png)
+
+ Sieve of Eratosthenes +
The idea behind is this: A number is prime, if none of the smaller prime numbers divides it. diff --git a/src/data_structures/fenwick.md b/src/data_structures/fenwick.md index 82755b452..439885b83 100644 --- a/src/data_structures/fenwick.md +++ b/src/data_structures/fenwick.md @@ -128,7 +128,9 @@ where $|$ is the bitwise OR operator. The following image shows a possible interpretation of the Fenwick tree as tree. The nodes of the tree show the ranges they cover. -
![Binary Indexed Tree](binary_indexed_tree.png)
+
+ Binary Indexed Tree +
## Implementation diff --git a/src/geometry/basic-geometry.md b/src/geometry/basic-geometry.md index 4c052a784..89acb1642 100644 --- a/src/geometry/basic-geometry.md +++ b/src/geometry/basic-geometry.md @@ -112,7 +112,9 @@ The dot (or scalar) product $\mathbf a \cdot \mathbf b$ for vectors $\mathbf a$ Geometrically it is product of the length of the first vector by the length of the projection of the second vector onto the first one. As you may see from the image below this projection is nothing but $|\mathbf a| \cos \theta$ where $\theta$ is the angle between $\mathbf a$ and $\mathbf b$. Thus $\mathbf a\cdot \mathbf b = |\mathbf a| \cos \theta \cdot |\mathbf b|$. -
![](https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Dot_Product.svg/300px-Dot_Product.svg.png)
+
+ +
The dot product holds some notable properties: @@ -181,7 +183,9 @@ To see the next important property we should take a look at the set of points $\ You can see that this set of points is exactly the set of points for which the projection onto $\mathbf a$ is the point $C \cdot \dfrac{\mathbf a}{|\mathbf a|}$ and they form a hyperplane orthogonal to $\mathbf a$. You can see the vector $\mathbf a$ alongside with several such vectors having same dot product with it in 2D on the picture below: -
![Vectors having same dot product with a](https://i.imgur.com/eyO7St4.png)
+
+ Vectors having same dot product with a +
In 2D these vectors will form a line, in 3D they will form a plane. Note that this result allows us to define a line in 2D as $\mathbf r\cdot \mathbf n=C$ or $(\mathbf r - \mathbf r_0)\cdot \mathbf n=0$ where $\mathbf n$ is vector orthogonal to the line and $\mathbf r_0$ is any vector already present on the line and $C = \mathbf r_0\cdot \mathbf n$. @@ -192,14 +196,18 @@ In the same manner a plane can be defined in 3D. ### Definition Assume you have three vectors $\mathbf a$, $\mathbf b$ and $\mathbf c$ in 3D space joined in a parallelepiped as in the picture below: -
![Three vectors](https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Parallelepiped_volume.svg/240px-Parallelepiped_volume.svg.png)
+
+ Three vectors +
How would you calculate its volume? From school we know that we should multiply the area of the base with the height, which is projection of $\mathbf a$ onto direction orthogonal to base. That means that if we define $\mathbf b \times \mathbf c$ as the vector which is orthogonal to both $\mathbf b$ and $\mathbf c$ and which length is equal to the area of the parallelogram formed by $\mathbf b$ and $\mathbf c$ then $|\mathbf a\cdot (\mathbf b\times\mathbf c)|$ will be equal to the volume of the parallelepiped. For integrity we will say that $\mathbf b\times \mathbf c$ will be always directed in such way that the rotation from the vector $\mathbf b$ to the vector $\mathbf c$ from the point of $\mathbf b\times \mathbf c$ is always counter-clockwise (see the picture below). -
![cross product](https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Cross_product_vector.svg/250px-Cross_product_vector.svg.png)
+
+ cross product +
This defines the cross (or vector) product $\mathbf b\times \mathbf c$ of the vectors $\mathbf b$ and $\mathbf c$ and the triple product $\mathbf a\cdot(\mathbf b\times \mathbf c)$ of the vectors $\mathbf a$, $\mathbf b$ and $\mathbf c$. diff --git a/src/geometry/convex_hull_trick.md b/src/geometry/convex_hull_trick.md index f9c938fb1..052073e2c 100644 --- a/src/geometry/convex_hull_trick.md +++ b/src/geometry/convex_hull_trick.md @@ -17,7 +17,9 @@ The idea of this approach is to maintain a lower convex hull of linear functions Actually it would be a bit more convenient to consider them not as linear functions, but as points $(k;b)$ on the plane such that we will have to find the point which has the least dot product with a given point $(x;1)$, that is, for this point $kx+b$ is minimized which is the same as initial problem. Such minimum will necessarily be on lower convex envelope of these points as can be seen below: -
![lower convex hull](convex_hull_trick.png)
+
+ lower convex hull +
One has to keep points on the convex hull and normal vectors of the hull's edges. When you have a $(x;1)$ query you'll have to find the normal vector closest to it in terms of angles between them, then the optimum linear function will correspond to one of its endpoints. @@ -90,7 +92,9 @@ Assume we're in some vertex corresponding to half-segment $[l,r)$ and the functi Here is the illustration of what is going on in the vertex when we add new function: -
![Li Chao Tree vertex](li_chao_vertex.png)
+
+ Li Chao Tree vertex +
Let's go to implementation now. Once again we will use complex numbers to keep linear functions. diff --git a/src/geometry/delaunay.md b/src/geometry/delaunay.md index c5f5c22d1..68d67ce8f 100644 --- a/src/geometry/delaunay.md +++ b/src/geometry/delaunay.md @@ -30,7 +30,9 @@ Because of the duality, we only need a fast algorithm to compute only one of $V$ ## Quad-edge data structure During the algorithm $D$ will be stored inside the quad-edge data structure. This structure is described in the picture: -
![Quad-Edge](quad-edge.png)
+
+ Quad-Edge +
In the algorithm we will use the following functions on edges: diff --git a/src/geometry/intersecting_segments.md b/src/geometry/intersecting_segments.md index a5eba5f6b..ac26c8fd5 100644 --- a/src/geometry/intersecting_segments.md +++ b/src/geometry/intersecting_segments.md @@ -16,18 +16,24 @@ The naive solution algorithm is to iterate over all pairs of segments in $O(n^2) Let's draw a vertical line $x = -\infty$ mentally and start moving this line to the right. In the course of its movement, this line will meet with segments, and at each time a segment intersect with our line it intersects in exactly one point (we will assume that there are no vertical segments). -
![sweep line and line segment intersection](sweep_line_1.png)
+
+ sweep line and line segment intersection +
Thus, for each segment, at some point in time, its point will appear on the sweep line, then with the movement of the line, this point will move, and finally, at some point, the segment will disappear from the line. We are interested in the **relative order of the segments** along the vertical. Namely, we will store a list of segments crossing the sweep line at a given time, where the segments will be sorted by their $y$-coordinate on the sweep line. -
![relative order of the segments across sweep line](sweep_line_2.png)
+
+ relative order of the segments across sweep line +
This order is interesting because intersecting segments will have the same $y$-coordinate at least at one time: -
![intersection point having same y-coordinate](sweep_line_3.png)
+
+ intersection point having same y-coordinate +
We formulate key statements: diff --git a/src/geometry/lattice-points.md b/src/geometry/lattice-points.md index 8bd9db346..e3d6faf7e 100644 --- a/src/geometry/lattice-points.md +++ b/src/geometry/lattice-points.md @@ -38,7 +38,9 @@ We have two cases: This amount is the same as the number of points such that $0 < y \leq (k - \lfloor k \rfloor) \cdot x + (b - \lfloor b \rfloor)$. So we reduced our problem to $k'= k - \lfloor k \rfloor$, $b' = b - \lfloor b \rfloor$ and both $k'$ and $b'$ less than $1$ now. Here is a picture, we just summed up blue points and subtracted the blue linear function from the black one to reduce problem to smaller values for $k$ and $b$: -
![Subtracting floored linear function](lattice.png)
+
+ Subtracting floored linear function +
- $k < 1$ and $b < 1$. @@ -51,7 +53,9 @@ We have two cases: which returns us back to the case $k>1$. You can see new reference point $O'$ and axes $X'$ and $Y'$ in the picture below: -
![New reference and axes](mirror.png)
+
+ New reference and axes +
As you see, in new reference system linear function will have coefficient $\tfrac 1 k$ and its zero will be in the point $\lfloor k\cdot n + b \rfloor-(k\cdot n+b)$ which makes formula above correct. ## Complexity analysis diff --git a/src/geometry/manhattan-distance.md b/src/geometry/manhattan-distance.md index 2aeb746af..4c725626e 100644 --- a/src/geometry/manhattan-distance.md +++ b/src/geometry/manhattan-distance.md @@ -12,7 +12,9 @@ $$d(p,q) = |x_p - x_q| + |y_p - y_q|$$ Defined this way, the distance corresponds to the so-called [Manhattan (taxicab) geometry](https://en.wikipedia.org/wiki/Taxicab_geometry), in which the points are considered intersections in a well designed city, like Manhattan, where you can only move on the streets horizontally or vertically, as shown in the image below: -
![Manhattan Distance](https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Manhattan_distance.svg/220px-Manhattan_distance.svg.png)
+
+ Manhattan Distance +
This images show some of the smallest paths from one black point to the other, all of them with length $12$. @@ -77,7 +79,9 @@ Also, we may realize that $\alpha$ is a [spiral similarity](https://en.wikipedia Here's an image to help visualizing the transformation: -
![Chebyshev transformation](chebyshev-transformation.png)
+
+ Chebyshev transformation +
## Manhattan Minimum Spanning Tree diff --git a/src/geometry/minkowski.md b/src/geometry/minkowski.md index d3fd93d5d..f2661d867 100644 --- a/src/geometry/minkowski.md +++ b/src/geometry/minkowski.md @@ -41,7 +41,9 @@ We repeat the following steps while $i < |P|$ or $j < |Q|$. Here is a nice visualization, which may help you understand what is going on. -
![Visual](minkowski.gif)
+
+ Visual +
## Distance between two polygons One of the most common applications of Minkowski sum is computing the distance between two convex polygons (or simply checking whether they intersect). diff --git a/src/geometry/planar.md b/src/geometry/planar.md index 017399a7c..2cfc81282 100644 --- a/src/geometry/planar.md +++ b/src/geometry/planar.md @@ -53,7 +53,9 @@ It's quite clear that the complexity of the algorithm is $O(m \log m)$ because o At the first glance it may seem that finding faces of a disconnected graph is not much harder because we can run the same algorithm for each connected component. However, the components may be drawn in a nested way, forming **holes** (see the image below). In this case the inner face of some component becomes the outer face of some other components and has a complex disconnected border. Dealing with such cases is quite hard, one possible approach is to identify nested components with [point location](point-location.md) algorithms. -
![Planar graph with holes](planar_hole.png)
+
+ Planar graph with holes +
## Implementation The following implementation returns a vector of vertices for each face, outer face goes first. @@ -147,7 +149,9 @@ std::vector> find_faces(std::vector vertices, std::ve Sometimes you are not given a graph explicitly, but rather as a set of line segments on a plane, and the actual graph is formed by intersecting those segments, as shown in the picture below. In this case you have to build the graph manually. The easiest way to do so is as follows. Fix a segment and intersect it with all other segments. Then sort all intersection points together with the two endpoints of the segment lexicographically and add them to the graph as vertices. Also link each two adjacent vertices in lexicographical order by an edge. After doing this procedure for all edges we will obtain the graph. Of course, we should ensure that two equal intersection points will always correspond to the same vertex. The easiest way to do this is to store the points in a map by their coordinates, regarding points whose coordinates differ by a small number (say, less than $10^{-9}$) as equal. This algorithm works in $O(n^2 \log n)$. -
![Implicitly defined graph](planar_implicit.png)
+
+ Implicitly defined graph +
## Implementation ```{.cpp file=planar_implicit} diff --git a/src/geometry/point-location.md b/src/geometry/point-location.md index 10c0d3f51..c6d21b7f8 100644 --- a/src/geometry/point-location.md +++ b/src/geometry/point-location.md @@ -15,7 +15,9 @@ This problem may arise when you need to locate some points in a Voronoi diagram Firstly, for each query point $p\ (x_0, y_0)$ we want to find such an edge that if the point belongs to any edge, the point lies on the edge we found, otherwise this edge must intersect the line $x = x_0$ at some unique point $(x_0, y)$ where $y < y_0$ and this $y$ is maximum among all such edges. The following image shows both cases. -
![Image of Goal](point_location_goal.png)
+
+ Image of Goal +
We will solve this problem offline using the sweep line algorithm. Let's iterate over x-coordinates of query points and edges' endpoints in increasing order and keep a set of edges $s$. For each x-coordinate we will add some events beforehand. @@ -27,7 +29,9 @@ Finally, for each query point we will add one _get_ event for its x-coordinate. For each x-coordinate we will sort the events by their types in order (_vertical_, _get_, _remove_, _add_). The following image shows all events in sorted order for each x-coordinate. -
![Image of Events](point_location_events.png)
+
+ Image of Events +
We will keep two sets during the sweep-line process. A set $t$ for all non-vertical edges, and one set $vert$ especially for the vertical ones. diff --git a/src/geometry/tangents-to-two-circles.md b/src/geometry/tangents-to-two-circles.md index 4f4dfa4e9..546150a62 100644 --- a/src/geometry/tangents-to-two-circles.md +++ b/src/geometry/tangents-to-two-circles.md @@ -14,7 +14,9 @@ The described algorithm will also work in the case when one (or both) circles de ## The number of common tangents The number of common tangents to two circles can be **0,1,2,3,4** and **infinite**. Look at the images for different cases. -
!["Different cases of tangents common to two circles"](tangents-to-two-circles.png)
+
+ +
Here, we won't be considering **degenerate** cases, i.e *when the circles coincide (in this case they have infinitely many common tangents), or one circle lies inside the other (in this case they have no common tangents, or if the circles are tangent, there is one common tangent).* diff --git a/src/geometry/vertical_decomposition.md b/src/geometry/vertical_decomposition.md index 934db8044..96853994f 100644 --- a/src/geometry/vertical_decomposition.md +++ b/src/geometry/vertical_decomposition.md @@ -39,7 +39,9 @@ For simplicity we will show how to do this for an upper segment, the algorithm f Here is a graphic representation of the three cases. -
![Visual](triangle_union.png)
+
+ Visual +
Finally we should remark on processing all the additions of $1$ or $-1$ on all stripes in $[x_1, x_2]$. For each addition of $w$ on $[x_1, x_2]$ we can create events $(x_1, w),\ (x_2, -w)$ and process all these events with a sweep line. diff --git a/src/graph/2SAT.md b/src/graph/2SAT.md index b66316bbe..fbd1a6a35 100644 --- a/src/graph/2SAT.md +++ b/src/graph/2SAT.md @@ -39,7 +39,9 @@ b \Rightarrow a & \lnot b \Rightarrow \lnot a & b \Rightarrow \lnot a & c \Right You can see the implication graph in the following image: -
!["Implication Graph of 2-SAT example"](2SAT.png)
+
+ +
It is worth paying attention to the property of the implication graph: if there is an edge $a \Rightarrow b$, then there also is an edge $\lnot b \Rightarrow \lnot a$. @@ -59,7 +61,9 @@ The following image shows all strongly connected components for the example. As we can check easily, neither of the four components contain a vertex $x$ and its negation $\lnot x$, therefore the example has a solution. We will learn in the next paragraphs how to compute a valid assignment, but just for demonstration purposes the solution $a = \text{false}$, $b = \text{false}$, $c = \text{false}$ is given. -
!["Strongly Connected Components of the 2-SAT example"](2SAT_SCC.png)
+
+ +
Now we construct the algorithm for finding the solution of the 2-SAT problem on the assumption that the solution exists. diff --git a/src/graph/edmonds_karp.md b/src/graph/edmonds_karp.md index ef844f970..a86a475f9 100644 --- a/src/graph/edmonds_karp.md +++ b/src/graph/edmonds_karp.md @@ -43,7 +43,9 @@ The source $s$ is origin of all the water, and the water can only drain in the s The following image shows a flow network. The first value of each edge represents the flow, which is initially 0, and the second value represents the capacity. -
![Flow network](Flow1.png)
+
+ Flow network +
The value of the flow of a network is the sum of all the flows that get produced in the source $s$, or equivalently to the sum of all the flows that are consumed by the sink $t$. A **maximal flow** is a flow with the maximal possible value. @@ -53,7 +55,9 @@ In the visualization with water pipes, the problem can be formulated in the foll how much water can we push through the pipes from the source to the sink? The following image shows the maximal flow in the flow network. -
![Maximal flow](Flow9.png)
+
+ Maximal flow +
## Ford-Fulkerson method @@ -79,7 +83,9 @@ we update $f((u, v)) ~\text{+=}~ C$ and $f((v, u)) ~\text{-=}~ C$ for every edge Here is an example to demonstrate the method. We use the same flow network as above. Initially we start with a flow of 0. -
![Flow network](Flow1.png)
+
+ Flow network +
We can find the path $s - A - B - t$ with the residual capacities 7, 5, and 8. Their minimum is 5, therefore we can increase the flow along this path by 5. @@ -200,7 +206,9 @@ It says that the capacity of the maximum flow has to be equal to the capacity of In the following image, you can see the minimum cut of the flow network we used earlier. It shows that the capacity of the cut $\{s, A, D\}$ and $\{B, C, t\}$ is $5 + 3 + 2 = 10$, which is equal to the maximum flow that we found. Other cuts will have a bigger capacity, like the capacity between $\{s, A\}$ and $\{B, C, D, t\}$ is $4 + 3 + 5 = 12$. -
![Minimum cut](Cut.png)
+
+ Minimum cut +
A minimum cut can be found after performing a maximum flow computation using the Ford-Fulkerson method. One possible minimum cut is the following: diff --git a/src/graph/hld.md b/src/graph/hld.md index bd56798fd..36caf852e 100644 --- a/src/graph/hld.md +++ b/src/graph/hld.md @@ -53,7 +53,9 @@ Since we can move from one heavy path to another only through a light edge (each The following image illustrates the decomposition of a sample tree. The heavy edges are thicker than the light edges. The heavy paths are marked by dotted boundaries. -
![Image of HLD](hld.png)
+
+ Image of HLD +
## Sample problems diff --git a/src/graph/lca.md b/src/graph/lca.md index db36c18a0..f577d4b2f 100644 --- a/src/graph/lca.md +++ b/src/graph/lca.md @@ -30,7 +30,9 @@ So the $\text{LCA}(v_1, v_2)$ can be uniquely determined by finding the vertex w Let's illustrate this idea. Consider the following graph and the Euler tour with the corresponding heights: -
![LCA_Euler_Tour](LCA_Euler.png)
+
+ LCA_Euler_Tour +
$$\begin{array}{|l|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline diff --git a/src/graph/lca_farachcoltonbender.md b/src/graph/lca_farachcoltonbender.md index f67365511..506509359 100644 --- a/src/graph/lca_farachcoltonbender.md +++ b/src/graph/lca_farachcoltonbender.md @@ -22,7 +22,9 @@ The LCA of two nodes $u$ and $v$ is the node between the occurrences of $u$ and In the following picture you can see a possible Euler-Tour of a graph and in the list below you can see the visited nodes and their heights. -
![LCA_Euler_Tour](LCA_Euler.png)
+
+ LCA_Euler_Tour +
$$\begin{array}{|l|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline diff --git a/src/graph/rmq_linear.md b/src/graph/rmq_linear.md index 9ce17f341..ab0ae216a 100644 --- a/src/graph/rmq_linear.md +++ b/src/graph/rmq_linear.md @@ -24,7 +24,9 @@ The array `A` will be partitioned into 3 parts: the prefix of the array up to th The root of the tree will be a node corresponding to the minimum element of the array `A`, the left subtree will be the Cartesian tree of the prefix, and the right subtree will be a Cartesian tree of the suffix. In the following image you can see one array of length 10 and the corresponding Cartesian tree. -
![Image of Cartesian Tree](CartesianTree.png)
+
+ Image of Cartesian Tree +
The range minimum query `[l, r]` is equivalent to the lowest common ancestor query `[l', r']`, where `l'` is the node corresponding to the element `A[l]` and `r'` the node corresponding to the element `A[r]`. Indeed the node corresponding to the smallest element in the range has to be an ancestor of all nodes in the range, therefor also from `l'` and `r'`. @@ -33,7 +35,9 @@ And is also has to be the lowest ancestor, because otherwise `l'` and `r'` would In the following image you can see the LCA queries for the RMQ queries `[1, 3]` and `[5, 9]`. In the first query the LCA of the nodes `A[1]` and `A[3]` is the node corresponding to `A[2]` which has the value 2, and in the second query the LCA of `A[5]` and `A[9]` is the node corresponding to `A[8]` which has the value 3. -
![LCA queries in the Cartesian Tree](CartesianTreeLCA.png)
+
+ LCA queries in the Cartesian Tree +
Such a tree can be built in $O(N)$ time and the Farach-Colton and Benders algorithm can preprocess the tree in $O(N)$ and find the LCA in $O(1)$. diff --git a/src/graph/topological-sort.md b/src/graph/topological-sort.md index acfad5331..909e40652 100644 --- a/src/graph/topological-sort.md +++ b/src/graph/topological-sort.md @@ -20,9 +20,9 @@ Here is one given graph together with its topological order: Topological order can be **non-unique** (for example, if there exist three vertices $a$, $b$, $c$ for which there exist paths from $a$ to $b$ and from $a$ to $c$ but not paths from $b$ to $c$ or from $c$ to $b$). The example graph also has multiple topological orders, a second topological order is the following: -
-![second topological order](topological_3.png) -
+
+ second topological order +
A Topological order may **not exist** at all. It only exists, if the directed graph contains no cycles. diff --git a/src/others/stern_brocot_tree_farey_sequences.md b/src/others/stern_brocot_tree_farey_sequences.md index bb9dfd725..f725de53b 100644 --- a/src/others/stern_brocot_tree_farey_sequences.md +++ b/src/others/stern_brocot_tree_farey_sequences.md @@ -34,7 +34,9 @@ Continuing this process to infinity this covers *all* positive fractions. Additi Before proving these properties, let us actually show a visualization of the Stern-Brocot tree, rather than the list representation. Every fraction in the tree has two children. Each child is the mediant of the closest ancestor on the left and closest ancestor to the right. -
![Stern-Brocot tree](https://upload.wikimedia.org/wikipedia/commons/thumb/3/37/SternBrocotTree.svg/1024px-SternBrocotTree.svg.png)
+
+ Stern-Brocot tree +
## Proofs diff --git a/src/others/tortoise_and_hare.md b/src/others/tortoise_and_hare.md index 9d2ba0a96..783185542 100644 --- a/src/others/tortoise_and_hare.md +++ b/src/others/tortoise_and_hare.md @@ -7,7 +7,9 @@ tags: Given a linked list where the starting point of that linked list is denoted by **head**, and there may or may not be a cycle present. For instance: -
!["Linked list with cycle"](tortoise_hare_algo.png)
+
+ +
Here we need to find out the point **C**, i.e the starting point of the cycle. @@ -27,7 +29,9 @@ So, it involved two steps: 6. If they point to any same node at any point of their journey, it would indicate that the cycle indeed exists in the linked list. 7. If we get null, it would indicate that the linked list has no cycle. -
!["Found cycle"](tortoise_hare_cycle_found.png)
+
+ +
Now, that we have figured out that there is a cycle present in the linked list, for the next step we need to find out the starting point of cycle, i.e., **C**. ### Step 2: Starting point of the cycle @@ -81,7 +85,9 @@ When the slow pointer has moved $k \cdot L$ steps, and the fast pointer has cove Lets try to calculate the distance covered by both of the pointers till they point they met within the cycle. -
!["Proof"](tortoise_hare_proof.png)
+
+ +
$slowDist = a + xL + b$ , $x\ge0$ From a1adc156765822f6f53c5d2cb432ae0818c00882 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Tue, 15 Apr 2025 20:31:59 -0400 Subject: [PATCH 21/86] Update k-th.md #1215 basics solved. --- src/sequences/k-th.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sequences/k-th.md b/src/sequences/k-th.md index 02b0c0ec2..0f588c5cb 100644 --- a/src/sequences/k-th.md +++ b/src/sequences/k-th.md @@ -68,7 +68,7 @@ T order_statistics (std::vector a, unsigned n, unsigned k) ## Notes * The randomized algorithm above is named [quickselect](https://en.wikipedia.org/wiki/Quickselect). You should do random shuffle on $A$ before calling it or use a random element as a barrier for it to run properly. There are also deterministic algorithms that solve the specified problem in linear time, such as [median of medians](https://en.wikipedia.org/wiki/Median_of_medians). -* A deterministic linear solution is implemented in C++ standard library as [std::nth_element](https://en.cppreference.com/w/cpp/algorithm/nth_element). +* [std::nth_element](https://en.cppreference.com/w/cpp/algorithm/nth_element) solves this in C++ but gcc's implementation runs in worst case $O(n \log n )$ time. * Finding $K$ smallest elements can be reduced to finding $K$-th element with a linear overhead, as they're exactly the elements that are smaller than $K$-th. ## Practice Problems From a65db14a555810306ec6af024bc9f0afd2e0a60b Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Tue, 15 Apr 2025 20:46:24 -0400 Subject: [PATCH 22/86] Update finding-negative-cycle-in-graph.md Resolves 1419. --- src/graph/finding-negative-cycle-in-graph.md | 21 +++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/graph/finding-negative-cycle-in-graph.md b/src/graph/finding-negative-cycle-in-graph.md index 7589c09db..a9b87c7f9 100644 --- a/src/graph/finding-negative-cycle-in-graph.md +++ b/src/graph/finding-negative-cycle-in-graph.md @@ -30,35 +30,33 @@ Do $N$ iterations of Bellman-Ford algorithm. If there were no changes on the las struct Edge { int a, b, cost; }; - -int n, m; + +int n; vector edges; const int INF = 1000000000; - + void solve() { - vector d(n, INF); + vector d(n, 0); vector p(n, -1); int x; - - d[0] = 0; - + for (int i = 0; i < n; ++i) { x = -1; for (Edge e : edges) { - if (d[e.a] < INF && d[e.a] + e.cost < d[e.b]) { + if (d[e.a] + e.cost < d[e.b]) { d[e.b] = max(-INF, d[e.a] + e.cost); p[e.b] = e.a; x = e.b; } } } - + if (x == -1) { cout << "No negative cycle found."; } else { for (int i = 0; i < n; ++i) x = p[x]; - + vector cycle; for (int v = x;; v = p[v]) { cycle.push_back(v); @@ -66,14 +64,13 @@ void solve() { break; } reverse(cycle.begin(), cycle.end()); - + cout << "Negative cycle: "; for (int v : cycle) cout << v << ' '; cout << endl; } } - ``` ## Using Floyd-Warshall algorithm From b21558de0edde5d4edb1954b565fc6e10b24f5ee Mon Sep 17 00:00:00 2001 From: Mrityunjai Singh Date: Wed, 16 Apr 2025 01:32:22 -0700 Subject: [PATCH 23/86] aho corasick text change --- src/string/aho_corasick.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string/aho_corasick.md b/src/string/aho_corasick.md index d56ed5c1c..df0998713 100644 --- a/src/string/aho_corasick.md +++ b/src/string/aho_corasick.md @@ -209,7 +209,7 @@ Assume that at the moment we stand in a vertex $v$ and consider a character $c$. 1. $go[v][c] = -1$. In this case, we may assign $go[v][c] = go[u][c]$, which is already known by the induction hypothesis; 2. $go[v][c] = w \neq -1$. In this case, we may assign $link[w] = go[u][c]$. -In this way, we spend $O(1)$ time per each pair of a vertex and a character, making the running time $O(mk)$. The major overhead here is that we copy a lot of transitions from $u$ in the first case, while the transitions of the second case form the trie and sum up to $m$ over all vertices. To avoid the copying of $go[u][c]$, we may use a persistent array data structure, using which we initially copy $go[u]$ into $go[v]$ and then only update values for characters in which the transition would differ. This leads to the $O(m \log k)$ algorithm. +In this way, we spend $O(1)$ time per each pair of a vertex and a character, making the running time $O(mk)$. The major overhead here is that we copy a lot of transitions from $u$ in the first case, while the transitions of the second case form the trie and sum up to $m$ over all vertices. To avoid the copying of $go[u][c]$, we may use a persistent array data structure, using which we initially copy $go[u]$ into $go[v]$ and then only update values for characters in which the transition would differ. This leads to the $O(n \log k)$ algorithm. ## Applications From 4cdc4df2c108f77037a5e0b5e508de7548ec7c8d Mon Sep 17 00:00:00 2001 From: jxu <7989982+jxu@users.noreply.github.com> Date: Thu, 17 Apr 2025 13:52:46 -0400 Subject: [PATCH 24/86] Fibonacci: better motivation for matrix form --- src/algebra/fibonacci-numbers.md | 43 ++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/algebra/fibonacci-numbers.md b/src/algebra/fibonacci-numbers.md index 22403419a..adc409d3e 100644 --- a/src/algebra/fibonacci-numbers.md +++ b/src/algebra/fibonacci-numbers.md @@ -116,9 +116,48 @@ In this way, we obtain a linear solution, $O(n)$ time, saving all the values pri ### Matrix form -It is easy to prove the following relation: +To go from $(F_n, F_{n-1})$ to $(F_{n+1}, F_n)$, we can express the linear recurrence as a 2x2 matrix multiplication: -$$\begin{pmatrix} 1 & 1 \cr 1 & 0 \cr\end{pmatrix} ^ n = \begin{pmatrix} F_{n+1} & F_{n} \cr F_{n} & F_{n-1} \cr\end{pmatrix}$$ +$$ +\begin{pmatrix} +1 & 1 \\ +1 & 0 +\end{pmatrix} +\begin{pmatrix} +F_n \\ +F_{n-1} +\end{pmatrix} += +\begin{pmatrix} +F_n + F_{n-1} \\ +F_{n} +\end{pmatrix} += +\begin{pmatrix} +F_{n+1} \\ +F_{n} +\end{pmatrix} +$$ + +This lets us treat iterating the recurrence as repeated matrix multiplication, which has nice properties. In particular, + +$$ +\begin{pmatrix} +1 & 1 \\ +1 & 0 +\end{pmatrix}^n +\begin{pmatrix} +F_1 \\ +F_0 +\end{pmatrix} += +\begin{pmatrix} +F_{n+1} \\ +F_{n} +\end{pmatrix} +$$ + +where $F_1 = 1, F_0 = 0$. Thus, in order to find $F_n$ in $O(log n)$ time, we must raise the matrix to n. (See [Binary exponentiation](binary-exp.md)) From 7520d3e539694f053614ed9e8e1fd3bf980338c7 Mon Sep 17 00:00:00 2001 From: jxu <7989982+jxu@users.noreply.github.com> Date: Thu, 17 Apr 2025 14:03:29 -0400 Subject: [PATCH 25/86] Fibonacci: Cassini's identity proof sketches --- src/algebra/fibonacci-numbers.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/algebra/fibonacci-numbers.md b/src/algebra/fibonacci-numbers.md index 22403419a..7c805a629 100644 --- a/src/algebra/fibonacci-numbers.md +++ b/src/algebra/fibonacci-numbers.md @@ -22,6 +22,8 @@ Fibonacci numbers possess a lot of interesting properties. Here are a few of the $$F_{n-1} F_{n+1} - F_n^2 = (-1)^n$$ +This can be proved by induction. A one-line proof due to Knuth comes from taking the determinant of the 2x2 matrix form below. + * The "addition" rule: $$F_{n+k} = F_k F_{n+1} + F_{k-1} F_n$$ From 375ca6b9368247b01a0722a8d184418c3c5bebe1 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Fri, 18 Apr 2025 20:42:14 +0200 Subject: [PATCH 26/86] log n -> \log n --- src/algebra/fibonacci-numbers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/fibonacci-numbers.md b/src/algebra/fibonacci-numbers.md index adc409d3e..e63e52081 100644 --- a/src/algebra/fibonacci-numbers.md +++ b/src/algebra/fibonacci-numbers.md @@ -159,7 +159,7 @@ $$ where $F_1 = 1, F_0 = 0$. -Thus, in order to find $F_n$ in $O(log n)$ time, we must raise the matrix to n. (See [Binary exponentiation](binary-exp.md)) +Thus, in order to find $F_n$ in $O(\log n)$ time, we must raise the matrix to n. (See [Binary exponentiation](binary-exp.md)) ```{.cpp file=fibonacci_matrix} struct matrix { From 8c5bc69c37613441b49493974c9bfa7b04aa7deb Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Fri, 18 Apr 2025 23:47:45 +0200 Subject: [PATCH 27/86] m -> n in Aho-Corasick --- src/string/aho_corasick.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string/aho_corasick.md b/src/string/aho_corasick.md index df0998713..36ec40c7d 100644 --- a/src/string/aho_corasick.md +++ b/src/string/aho_corasick.md @@ -209,7 +209,7 @@ Assume that at the moment we stand in a vertex $v$ and consider a character $c$. 1. $go[v][c] = -1$. In this case, we may assign $go[v][c] = go[u][c]$, which is already known by the induction hypothesis; 2. $go[v][c] = w \neq -1$. In this case, we may assign $link[w] = go[u][c]$. -In this way, we spend $O(1)$ time per each pair of a vertex and a character, making the running time $O(mk)$. The major overhead here is that we copy a lot of transitions from $u$ in the first case, while the transitions of the second case form the trie and sum up to $m$ over all vertices. To avoid the copying of $go[u][c]$, we may use a persistent array data structure, using which we initially copy $go[u]$ into $go[v]$ and then only update values for characters in which the transition would differ. This leads to the $O(n \log k)$ algorithm. +In this way, we spend $O(1)$ time per each pair of a vertex and a character, making the running time $O(nk)$. The major overhead here is that we copy a lot of transitions from $u$ in the first case, while the transitions of the second case form the trie and sum up to $n$ over all vertices. To avoid the copying of $go[u][c]$, we may use a persistent array data structure, using which we initially copy $go[u]$ into $go[v]$ and then only update values for characters in which the transition would differ. This leads to the $O(n \log k)$ algorithm. ## Applications From 115cc22af2ba00e76f123f2a382afc44ff9710d4 Mon Sep 17 00:00:00 2001 From: jxu <7989982+jxu@users.noreply.github.com> Date: Fri, 18 Apr 2025 23:11:59 -0400 Subject: [PATCH 28/86] Fibonacci: restore matrix power form Maybe a dotted line would show the matrix [[F2, F1],[F1,F0]] can be viewed as two column vectors. Using only the matrix power saves one matrix-vector multiply. --- src/algebra/fibonacci-numbers.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/algebra/fibonacci-numbers.md b/src/algebra/fibonacci-numbers.md index e63e52081..e1acfdcb0 100644 --- a/src/algebra/fibonacci-numbers.md +++ b/src/algebra/fibonacci-numbers.md @@ -157,7 +157,19 @@ F_{n} \end{pmatrix} $$ -where $F_1 = 1, F_0 = 0$. +where $F_1 = 1, F_0 = 0$. +In fact, since +$$ +\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} += \begin{pmatrix} F_2 & F_1 \\ F_1 & F_0 \end{pmatrix} +$$ + +we can use the matrix directly: + +$$ +\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^n += \begin{pmatrix} F_{n+1} & F_n \\ F_n & F_{n-1} \end{pmatrix} +$$ Thus, in order to find $F_n$ in $O(\log n)$ time, we must raise the matrix to n. (See [Binary exponentiation](binary-exp.md)) From 59c31747c57735cfe83639f9a1dac64bb800dd78 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Sat, 19 Apr 2025 09:56:55 +0200 Subject: [PATCH 29/86] Update src/algebra/fibonacci-numbers.md --- src/algebra/fibonacci-numbers.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/algebra/fibonacci-numbers.md b/src/algebra/fibonacci-numbers.md index e1acfdcb0..dd8e1bd1a 100644 --- a/src/algebra/fibonacci-numbers.md +++ b/src/algebra/fibonacci-numbers.md @@ -159,6 +159,7 @@ $$ where $F_1 = 1, F_0 = 0$. In fact, since + $$ \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} = \begin{pmatrix} F_2 & F_1 \\ F_1 & F_0 \end{pmatrix} From 06d6a835e50e0d66de3c817a322eb292e69d23d5 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Mon, 21 Apr 2025 21:11:00 -0400 Subject: [PATCH 30/86] Update fibonacci-numbers.md Try indentation. --- src/algebra/fibonacci-numbers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/fibonacci-numbers.md b/src/algebra/fibonacci-numbers.md index 7c805a629..176a73600 100644 --- a/src/algebra/fibonacci-numbers.md +++ b/src/algebra/fibonacci-numbers.md @@ -22,7 +22,7 @@ Fibonacci numbers possess a lot of interesting properties. Here are a few of the $$F_{n-1} F_{n+1} - F_n^2 = (-1)^n$$ -This can be proved by induction. A one-line proof due to Knuth comes from taking the determinant of the 2x2 matrix form below. +>This can be proved by induction. A one-line proof by Knuth comes from taking the determinant of the 2x2 matrix form below. * The "addition" rule: From 3de210a3040f8b2dab5cf64286f3c28e02747291 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Mon, 21 Apr 2025 22:11:52 -0400 Subject: [PATCH 31/86] updated script to account for when text follows center tag --- src/geometry/manhattan-distance.md | 28 ++++++++++++++++------------ src/graph/edmonds_karp.md | 20 ++++++++++++++++---- src/graph/mst_prim.md | 5 ++++- src/graph/second_best_mst.md | 6 ++++-- src/graph/topological-sort.md | 8 ++++---- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/geometry/manhattan-distance.md b/src/geometry/manhattan-distance.md index 4c725626e..87514868a 100644 --- a/src/geometry/manhattan-distance.md +++ b/src/geometry/manhattan-distance.md @@ -88,17 +88,19 @@ Here's an image to help visualizing the transformation: The Manhattan MST problem consists of, given some points in the plane, find the edges that connect all the points and have a minimum total sum of weights. The weight of an edge that connects two points is their Manhattan distance. For simplicity, we assume that all points have different locations. Here we show a way of finding the MST in $O(n \log{n})$ by finding for each point its nearest neighbor in each octant, as represented by the image below. This will give us $O(n)$ candidate edges, which, as we show below, will guarantee that they contain the MST. The final step is then using some standard MST, for example, [Kruskal algorithm using disjoint set union](https://cp-algorithms.com/graph/mst_kruskal_with_dsu.html). -
![8 octants picture](manhattan-mst-octants.png) - -*The 8 octants relative to a point S*
+
+ 8 octants picture + *The 8 octants relative to a point S* +
The algorithm shown here was first presented in a paper from [H. Zhou, N. Shenoy, and W. Nichollos (2002)](https://ieeexplore.ieee.org/document/913303). There is also another know algorithm that uses a Divide and conquer approach by [J. Stolfi](https://www.academia.edu/15667173/On_computing_all_north_east_nearest_neighbors_in_the_L1_metric), which is also very interesting and only differ in the way they find the nearest neighbor in each octant. They both have the same complexity, but the one presented here is easier to implement and has a lower constant factor. First, let's understand why it is enough to consider only the nearest neighbor in each octant. The idea is to show that for a point $s$ and any two other points $p$ and $q$ in the same octant, $d(p, q) < \max(d(s, p), d(s, q))$. This is important, because it shows that if there was a MST where $s$ is connected to both $p$ and $q$, we could erase one of these edges and add the edge $(p,q)$, which would decrease the total cost. To prove this, we assume without loss of generality that $p$ and $q$ are in the octanct $R_1$, which is defined by: $x_s \leq x$ and $x_s - y_s > x - y$, and then do some casework. The image below give some intuition on why this is true. -
![unique nearest neighbor](manhattan-mst-uniqueness.png) - -*Intuitively, the limitation of the octant makes it impossible that $p$ and $q$ are both closer to $s$ than to each other*
+
+ unique nearest neighbor + *Intuitively, the limitation of the octant makes it impossible that $p$ and $q$ are both closer to $s$ than to each other* +
Therefore, the main question is how to find the nearest neighbor in each octant for every single of the $n$ points. @@ -109,13 +111,15 @@ For simplicity we focus on the NNE octant ($R_1$ in the image above). All other We will use a sweep-line approach. We process the points from south-west to north-east, that is, by non-decreasing $x + y$. We also keep a set of points which don't have their nearest neighbor yet, which we call "active set". We add the images below to help visualize the algorithm. -
![manhattan-mst-sweep](manhattan-mst-sweep-line-1.png) - -*In black with an arrow you can see the direction of the line-sweep. All the points below this lines are in the active set, and the points above are still not processed. In green we see the points which are in the octant of the processed point. In red the points that are not in the searched octant.*
- -
![manhattan-mst-sweep](manhattan-mst-sweep-line-2.png) +
+ manhattan-mst-sweep + *In black with an arrow you can see the direction of the line-sweep. All the points below this lines are in the active set, and the points above are still not processed. In green we see the points which are in the octant of the processed point. In red the points that are not in the searched octant.* +
-*In this image we see the active set after processing the point $p$. Note that the $2$ green points of the previous image had $p$ in its north-north-east octant and are not in the active set anymore, because they already found their nearest neighbor.*
+
+ manhattan-mst-sweep + *In this image we see the active set after processing the point $p$. Note that the $2$ green points of the previous image had $p$ in its north-north-east octant and are not in the active set anymore, because they already found their nearest neighbor.* +
When we add a new point point $p$, for every point $s$ that has it in its octant we can safely assign $p$ as the nearest neighbor. This is true because their distance is $d(p,s) = |x_p - x_s| + |y_p - y_s| = (x_p + y_p) - (x_s + y_s)$, because $p$ is in the north-north-east octant. As all the next points will not have a smaller value of $x + y$ because of the sorting step, $p$ is guaranteed to have the smaller distance. We can then remove all such points from the active set, and finally add $p$ to the active set. diff --git a/src/graph/edmonds_karp.md b/src/graph/edmonds_karp.md index a86a475f9..c1f394dce 100644 --- a/src/graph/edmonds_karp.md +++ b/src/graph/edmonds_karp.md @@ -90,14 +90,23 @@ Initially we start with a flow of 0. We can find the path $s - A - B - t$ with the residual capacities 7, 5, and 8. Their minimum is 5, therefore we can increase the flow along this path by 5. This gives a flow of 5 for the network. -
![First path](Flow2.png) ![Network after first path](Flow3.png)
+
+ First path + ![Network after first path](Flow3.png) +
Again we look for an augmenting path, this time we find $s - D - A - C - t$ with the residual capacities 4, 3, 3, and 5. Therefore we can increase the flow by 3 and we get a flow of 8 for the network. -
![Second path](Flow4.png) ![Network after second path](Flow5.png)
+
+ Second path + ![Network after second path](Flow5.png) +
This time we find the path $s - D - C - B - t$ with the residual capacities 1, 2, 3, and 3, and hence, we increase the flow by 1. -
![Third path](Flow6.png) ![Network after third path](Flow7.png)
+
+ Third path + ![Network after third path](Flow7.png) +
This time we find the augmenting path $s - A - D - C - t$ with the residual capacities 2, 3, 1, and 2. We can increase the flow by 1. @@ -107,7 +116,10 @@ In the original flow network, we are not allowed to send any flow from $A$ to $D But because we already have a flow of 3 from $D$ to $A$, this is possible. The intuition of it is the following: Instead of sending a flow of 3 from $D$ to $A$, we only send 2 and compensate this by sending an additional flow of 1 from $s$ to $A$, which allows us to send an additional flow of 1 along the path $D - C - t$. -
![Fourth path](Flow8.png) ![Network after fourth path](Flow9.png)
+
+ Fourth path + ![Network after fourth path](Flow9.png) +
Now, it is impossible to find an augmenting path between $s$ and $t$, therefore this flow of $10$ is the maximal possible. We have found the maximal flow. diff --git a/src/graph/mst_prim.md b/src/graph/mst_prim.md index d8c3789db..9f7eb48c8 100644 --- a/src/graph/mst_prim.md +++ b/src/graph/mst_prim.md @@ -13,7 +13,10 @@ The spanning tree with the least weight is called a minimum spanning tree. In the left image you can see a weighted undirected graph, and in the right image you can see the corresponding minimum spanning tree. -
![Random graph](MST_before.png) ![MST of this graph](MST_after.png)
+
+ Random graph + ![MST of this graph](MST_after.png) +
It is easy to see that any spanning tree will necessarily contain $n-1$ edges. diff --git a/src/graph/second_best_mst.md b/src/graph/second_best_mst.md index 5e9c82246..075f0dd39 100644 --- a/src/graph/second_best_mst.md +++ b/src/graph/second_best_mst.md @@ -53,10 +53,12 @@ The final time complexity of this approach is $O(E \log V)$. For example: -
![MST](second_best_mst_1.png) ![Second best MST](second_best_mst_2.png)
+
+ MST + ![Second best MST](second_best_mst_2.png)
*In the image left is the MST and right is the second best MST.* -
+ In the given graph suppose we root the MST at the blue vertex on the top, and then run our algorithm by start picking the edges not in MST. diff --git a/src/graph/topological-sort.md b/src/graph/topological-sort.md index 909e40652..262189a42 100644 --- a/src/graph/topological-sort.md +++ b/src/graph/topological-sort.md @@ -13,10 +13,10 @@ In other words, you want to find a permutation of the vertices (**topological or Here is one given graph together with its topological order: -
-![example directed graph](topological_1.png) -![one topological order](topological_2.png) -
+
+ example directed graph + ![one topological order](topological_2.png) +
Topological order can be **non-unique** (for example, if there exist three vertices $a$, $b$, $c$ for which there exist paths from $a$ to $b$ and from $a$ to $c$ but not paths from $b$ to $c$ or from $c$ to $b$). The example graph also has multiple topological orders, a second topological order is the following: From 9f5502ad2af0b6320be0ae8b7e27cf32c5b2d6bc Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Mon, 21 Apr 2025 22:22:24 -0400 Subject: [PATCH 32/86] change 2 images rather than image then text --- src/graph/mst_prim.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/mst_prim.md b/src/graph/mst_prim.md index 9f7eb48c8..21649f28d 100644 --- a/src/graph/mst_prim.md +++ b/src/graph/mst_prim.md @@ -15,7 +15,7 @@ In the left image you can see a weighted undirected graph, and in the right imag
Random graph - ![MST of this graph](MST_after.png) + MST of this graph
It is easy to see that any spanning tree will necessarily contain $n-1$ edges. From fc8d5dc718a348a91a3d86e35ea8c64e8df47f00 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Mon, 21 Apr 2025 22:26:46 -0400 Subject: [PATCH 33/86] formatted multiple images in center tag --- src/graph/second_best_mst.md | 3 ++- src/graph/topological-sort.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/graph/second_best_mst.md b/src/graph/second_best_mst.md index 075f0dd39..3a68ee34a 100644 --- a/src/graph/second_best_mst.md +++ b/src/graph/second_best_mst.md @@ -55,7 +55,8 @@ For example:
MST - ![Second best MST](second_best_mst_2.png)
+ Second best MST +
*In the image left is the MST and right is the second best MST.*
diff --git a/src/graph/topological-sort.md b/src/graph/topological-sort.md index 262189a42..c522039bc 100644 --- a/src/graph/topological-sort.md +++ b/src/graph/topological-sort.md @@ -15,7 +15,7 @@ Here is one given graph together with its topological order:
example directed graph - ![one topological order](topological_2.png) + one topological order
Topological order can be **non-unique** (for example, if there exist three vertices $a$, $b$, $c$ for which there exist paths from $a$ to $b$ and from $a$ to $c$ but not paths from $b$ to $c$ or from $c$ to $b$). From f46a230f922fa344a7c5cce28292835ec315a454 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Mon, 21 Apr 2025 22:45:52 -0400 Subject: [PATCH 34/86] double images not working in edmonds karp --- src/graph/edmonds_karp.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/graph/edmonds_karp.md b/src/graph/edmonds_karp.md index c1f394dce..bab54772f 100644 --- a/src/graph/edmonds_karp.md +++ b/src/graph/edmonds_karp.md @@ -92,20 +92,20 @@ Their minimum is 5, therefore we can increase the flow along this path by 5. This gives a flow of 5 for the network.
First path - ![Network after first path](Flow3.png) + Network after first path
Again we look for an augmenting path, this time we find $s - D - A - C - t$ with the residual capacities 4, 3, 3, and 5. Therefore we can increase the flow by 3 and we get a flow of 8 for the network.
Second path - ![Network after second path](Flow5.png) + Network after second path
This time we find the path $s - D - C - B - t$ with the residual capacities 1, 2, 3, and 3, and hence, we increase the flow by 1.
Third path - ![Network after third path](Flow7.png) + Network after third path
This time we find the augmenting path $s - A - D - C - t$ with the residual capacities 2, 3, 1, and 2. @@ -118,7 +118,7 @@ The intuition of it is the following: Instead of sending a flow of 3 from $D$ to $A$, we only send 2 and compensate this by sending an additional flow of 1 from $s$ to $A$, which allows us to send an additional flow of 1 along the path $D - C - t$.
Fourth path - ![Network after fourth path](Flow9.png) + Network after fourth path
Now, it is impossible to find an augmenting path between $s$ and $t$, therefore this flow of $10$ is the maximal possible. From bee2358e0ea051328e6340babeeb57d1bd719c29 Mon Sep 17 00:00:00 2001 From: Proxihox Date: Thu, 1 May 2025 14:57:31 +0530 Subject: [PATCH 35/86] final fixes --- README.md | 2 +- src/num_methods/simulated_annealing.md | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 87fce368e..4bd8eacfc 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Compiled pages are published at [https://cp-algorithms.com/](https://cp-algorith ### New articles -- (19 October 2024) [Simulated Annealing](https://cp-algorithms.com/num_methods/simulated_annealing.html) +- (1 May 2025) [Simulated Annealing](https://cp-algorithms.com/num_methods/simulated_annealing.html) - (12 July 2024) [Manhattan distance](https://cp-algorithms.com/geometry/manhattan-distance.html) - (8 June 2024) [Knapsack Problem](https://cp-algorithms.com/dynamic_programming/knapsack.html) - (28 January 2024) [Introduction to Dynamic Programming](https://cp-algorithms.com/dynamic_programming/intro-to-dp.html) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index f9bd1686d..054f71fa4 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -16,7 +16,7 @@ We are given a function $E(s)$, which calculates the energy of the state $s$. We You are given a set of nodes in 2 dimensional space. Each node is characterised by its $x$ and $y$ coordinates. Your task is to find an ordering of the nodes, which will minimise the distance to be travelled when visiting these nodes in that order. ## Motivation -Annealing is a metallurgical process , wherein a material is heated up and allowed to cool, in order to allow the atoms inside to rearrange themselves in an arrangement with minimal internal energy, which in turn causes the material to have different properties. The state is the arrangement of atoms and the internal energy is the function being minimised. We can think of the original state of the atoms, as a local minima for its internal energy. To make the material rearrange its atoms, we need to motivate it to go across a region where its internal energy is not minimised in order to reach the global minima. This motivation is given by heating the material to a higher temperature. +Annealing is a metallurgical process, wherein a material is heated up and allowed to cool, in order to allow the atoms inside to rearrange themselves in an arrangement with minimal internal energy, which in turn causes the material to have different properties. The state is the arrangement of atoms and the internal energy is the function being minimised. We can think of the original state of the atoms, as a local minima for its internal energy. To make the material rearrange its atoms, we need to motivate it to go across a region where its internal energy is not minimised in order to reach the global minima. This motivation is given by heating the material to a higher temperature. Simulated annealing, literally, simulates this process. We start off with some random state (material) and set a high temperature (heat it up). Now, the algorithm is ready to accept states which have a higher energy than the current state, as it is motivated by the high temperature. This prevents the algorithm from getting stuck inside local minimas and move towards the global minima. As time progresses, the algorithm cools down and refuses the states with higher energy and moves into the closest minima it has found. @@ -26,7 +26,7 @@ $E(s)$ is the function which needs to be minimised (or maximised). It maps every ### State -The state space is the domain of the energy function, E(s), and a state is any element which belongs to the state space. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a state. +The state space is the domain of the energy function, $E(s)$, and a state is any element which belongs to the state space. In the case of TSP, all possible paths that we can take to visit all the nodes is the state space, and any single one of these paths can be considered as a state. ### Neighbouring state @@ -41,12 +41,11 @@ At the same time we also keep a track of the best state $s_{best}$ across all it

-A visual representation of simulated annealing, searching for the maxima of this function with multiple local maxima.. +A visual representation of simulated annealing, searching for the maxima of this function with multiple local maxima.
-This animation by [Kingpin13](https://commons.wikimedia.org/wiki/User:Kingpin13) is distributed under CC0 1.0 license.
-### Temperature($T$) and decay($u$) +### Temperature(T) and decay(u) The temperature of the system quantifies the willingness of the algorithm to accept a state with a higher energy. The decay is a constant which quantifies the "cooling rate" of the algorithm. A slow cooling rate (larger $u$) is known to give better results. @@ -107,8 +106,8 @@ pair simAnneal() { best = s; E_best = E_next; } + E = E_next; } - E = E_next; T *= u; } return {E_best, best}; @@ -158,7 +157,6 @@ class state { double E() { double dist = 0; - bool first = true; int n = points.size(); for (int i = 0;i < n; i++) dist += euclidean(points[i], points[(i+1)%n]); @@ -187,8 +185,8 @@ int main() { - The effect of the difference in energies, $E_{next} - E$, on the PAF can be increased/decreased by increasing/decreasing the base of the exponent as shown below: ```cpp bool P(double E, double E_next, double T, mt19937 rng) { - e = 2 // set e to any real number greater than 1 - double prob = exp(-(E_next-E)/T); + double e = 2 // set e to any real number greater than 1 + double prob = pow(e,-(E_next-E)/T); if (prob > 1) return true; else { From 46e4efa5180bfa059694dec086269806832105a7 Mon Sep 17 00:00:00 2001 From: Shashank Sahu <52148284+bit-shashank@users.noreply.github.com> Date: Sat, 3 May 2025 00:07:17 +0530 Subject: [PATCH 36/86] Typo fix in graph/fixed_length_paths.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced It is obvious that the constructed adjacency matrix if the answer to the problem for the case   $k = 1$ . It contains the number of paths of length   $1$  between each pair of vertices. To It is obvious that the constructed adjacency matrix is the answer to the problem for the case   $k = 1$ . It contains the number of paths of length   $1$  between each pair of vertices. --- src/graph/fixed_length_paths.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/fixed_length_paths.md b/src/graph/fixed_length_paths.md index e5ecf76bc..9e1c1efad 100644 --- a/src/graph/fixed_length_paths.md +++ b/src/graph/fixed_length_paths.md @@ -21,7 +21,7 @@ The following algorithm works also in the case of multiple edges: if some pair of vertices $(i, j)$ is connected with $m$ edges, then we can record this in the adjacency matrix by setting $G[i][j] = m$. Also the algorithm works if the graph contains loops (a loop is an edge that connect a vertex with itself). -It is obvious that the constructed adjacency matrix if the answer to the problem for the case $k = 1$. +It is obvious that the constructed adjacency matrix is the answer to the problem for the case $k = 1$. It contains the number of paths of length $1$ between each pair of vertices. We will build the solution iteratively: From 4611aee0bdc668908f5def6a51228b6a0ed51619 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Wed, 7 May 2025 17:57:39 -0400 Subject: [PATCH 37/86] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1d3f2be1..fb6e7afee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ Follow these steps to start contributing: 4. **Preview your changes** using the [preview page](preview.md) to ensure they look correct. 5. **Commit your changes** by clicking the _Propose changes_ button. 6. **Create a Pull Request (PR)** by clicking _Compare & pull request_. -7. **Review process**: Someone from the core team will review your changes. This may take a few hours to a few days. +7. **Review process**: Someone from the core team will review your changes. This may take a few days to a few weeks. ### Making Larger Changes From 27e90b5f3b84e58577f411d56a1e1582deb62850 Mon Sep 17 00:00:00 2001 From: t0wbo2t <52655804+t0wbo2t@users.noreply.github.com> Date: Thu, 15 May 2025 10:18:15 +0530 Subject: [PATCH 38/86] Update factorization.md [Update Powersmooth Definition] The definition of powersmooth was a bit confusing so I added a formal definition inspired by a number theory book. --- src/algebra/factorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/factorization.md b/src/algebra/factorization.md index 11bf4049c..51f206482 100644 --- a/src/algebra/factorization.md +++ b/src/algebra/factorization.md @@ -160,7 +160,7 @@ By looking at the squares $a^2$ modulo a fixed small number, it can be observed ## Pollard's $p - 1$ method { data-toc-label="Pollard's method" } It is very likely that at least one factor of a number is $B$**-powersmooth** for small $B$. -$B$-powersmooth means that every prime power $d^k$ that divides $p-1$ is at most $B$. +$B$-powersmooth means that every prime power $d^k$ that divides $p-1$ is at most $B$. Formally, let $\mathrm{B} \geqslant 1$ and $n \geqslant 1$ with prime factorization $n = \prod {p_i}^{e_i},$ then $n$ is $\mathrm{B}$-powersmooth if, for all $i,$ ${p_i}^{e_i} \leqslant \mathrm{B}$. E.g. the prime factorization of $4817191$ is $1303 \cdot 3697$. And the factors are $31$-powersmooth and $16$-powersmooth respectably, because $1303 - 1 = 2 \cdot 3 \cdot 7 \cdot 31$ and $3697 - 1 = 2^4 \cdot 3 \cdot 7 \cdot 11$. In 1974 John Pollard invented a method to extracts $B$-powersmooth factors from a composite number. From 6ec2fe6634b6e2bd4d879d08dfdf3bbcf87d0d6b Mon Sep 17 00:00:00 2001 From: 100daysummer <138024460+100daysummer@users.noreply.github.com> Date: Wed, 21 May 2025 12:00:17 +0300 Subject: [PATCH 39/86] Update longest_increasing_subsequence.md Small improvement of the wording of a question --- src/sequences/longest_increasing_subsequence.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sequences/longest_increasing_subsequence.md b/src/sequences/longest_increasing_subsequence.md index a4c8f0fe4..dca4f020b 100644 --- a/src/sequences/longest_increasing_subsequence.md +++ b/src/sequences/longest_increasing_subsequence.md @@ -174,7 +174,7 @@ We will again gradually process the numbers, first $a[0]$, then $a[1]$, etc, and $$ When we process $a[i]$, we can ask ourselves. -What have the conditions to be, that we write the current number $a[i]$ into the $d[0 \dots n]$ array? +Under what conditions should we write the current number $a[i]$ into the $d[0 \dots n]$ array? We set $d[l] = a[i]$, if there is a longest increasing sequence of length $l$ that ends in $a[i]$, and there is no longest increasing sequence of length $l$ that ends in a smaller number. Similar to the previous approach, if we remove the number $a[i]$ from the longest increasing sequence of length $l$, we get another longest increasing sequence of length $l -1$. From d1cfad25305a0047c822116f4369bdb33d157364 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Wed, 21 May 2025 13:11:00 +0200 Subject: [PATCH 40/86] semicolon after e --- src/num_methods/simulated_annealing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/simulated_annealing.md b/src/num_methods/simulated_annealing.md index 054f71fa4..bd0dd6ed2 100644 --- a/src/num_methods/simulated_annealing.md +++ b/src/num_methods/simulated_annealing.md @@ -185,7 +185,7 @@ int main() { - The effect of the difference in energies, $E_{next} - E$, on the PAF can be increased/decreased by increasing/decreasing the base of the exponent as shown below: ```cpp bool P(double E, double E_next, double T, mt19937 rng) { - double e = 2 // set e to any real number greater than 1 + double e = 2; // set e to any real number greater than 1 double prob = pow(e,-(E_next-E)/T); if (prob > 1) return true; From a82cd128a8f3040c8e2658c317f853f9d0ec2d8d Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Wed, 21 May 2025 13:11:36 +0200 Subject: [PATCH 41/86] update date --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4bd8eacfc..513e55f32 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Compiled pages are published at [https://cp-algorithms.com/](https://cp-algorith ### New articles -- (1 May 2025) [Simulated Annealing](https://cp-algorithms.com/num_methods/simulated_annealing.html) +- (21 May 2025) [Simulated Annealing](https://cp-algorithms.com/num_methods/simulated_annealing.html) - (12 July 2024) [Manhattan distance](https://cp-algorithms.com/geometry/manhattan-distance.html) - (8 June 2024) [Knapsack Problem](https://cp-algorithms.com/dynamic_programming/knapsack.html) - (28 January 2024) [Introduction to Dynamic Programming](https://cp-algorithms.com/dynamic_programming/intro-to-dp.html) From 422fb19bdd7c39a56d8fb51caefa419251b37fab Mon Sep 17 00:00:00 2001 From: t0wbo2t <52655804+t0wbo2t@users.noreply.github.com> Date: Wed, 21 May 2025 17:33:44 +0530 Subject: [PATCH 42/86] Update factorization.md [Update powersmooth definition with suggestions] Commas are now outside $...$ and definiton is for (p - 1) for consistency. --- src/algebra/factorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/factorization.md b/src/algebra/factorization.md index 51f206482..997a11be2 100644 --- a/src/algebra/factorization.md +++ b/src/algebra/factorization.md @@ -160,7 +160,7 @@ By looking at the squares $a^2$ modulo a fixed small number, it can be observed ## Pollard's $p - 1$ method { data-toc-label="Pollard's method" } It is very likely that at least one factor of a number is $B$**-powersmooth** for small $B$. -$B$-powersmooth means that every prime power $d^k$ that divides $p-1$ is at most $B$. Formally, let $\mathrm{B} \geqslant 1$ and $n \geqslant 1$ with prime factorization $n = \prod {p_i}^{e_i},$ then $n$ is $\mathrm{B}$-powersmooth if, for all $i,$ ${p_i}^{e_i} \leqslant \mathrm{B}$. +$B$-powersmooth means that every prime power $d^k$ that divides $p-1$ is at most $B$. Formally, let $\mathrm{B} \geqslant 1$ and let $p$ be a prime such that $(p - 1) \geqslant 1$. Suppose the prime factorization of $(p - 1)$ is $(p - 1) = \prod {q_i}^{e_i}$, where each $q_i$ is a prime and $e_i \geqslant 1$ then $(p - 1)$ is $\mathrm{B}$-powersmooth if, for all $i$, ${q_i}^{e_i} \leqslant \mathrm{B}$. E.g. the prime factorization of $4817191$ is $1303 \cdot 3697$. And the factors are $31$-powersmooth and $16$-powersmooth respectably, because $1303 - 1 = 2 \cdot 3 \cdot 7 \cdot 31$ and $3697 - 1 = 2^4 \cdot 3 \cdot 7 \cdot 11$. In 1974 John Pollard invented a method to extracts $B$-powersmooth factors from a composite number. From 1a7db31f720455b647a929596ff70936875f7532 Mon Sep 17 00:00:00 2001 From: t0wbo2t <52655804+t0wbo2t@users.noreply.github.com> Date: Thu, 22 May 2025 09:24:40 +0530 Subject: [PATCH 43/86] Update factorization.md [Update Pollard's (p - 1) Method] Updated materials related to powersmoothness. Corrected some minor mistakes. --- src/algebra/factorization.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/algebra/factorization.md b/src/algebra/factorization.md index 997a11be2..84bdd356d 100644 --- a/src/algebra/factorization.md +++ b/src/algebra/factorization.md @@ -159,11 +159,10 @@ By looking at the squares $a^2$ modulo a fixed small number, it can be observed ## Pollard's $p - 1$ method { data-toc-label="Pollard's method" } -It is very likely that at least one factor of a number is $B$**-powersmooth** for small $B$. -$B$-powersmooth means that every prime power $d^k$ that divides $p-1$ is at most $B$. Formally, let $\mathrm{B} \geqslant 1$ and let $p$ be a prime such that $(p - 1) \geqslant 1$. Suppose the prime factorization of $(p - 1)$ is $(p - 1) = \prod {q_i}^{e_i}$, where each $q_i$ is a prime and $e_i \geqslant 1$ then $(p - 1)$ is $\mathrm{B}$-powersmooth if, for all $i$, ${q_i}^{e_i} \leqslant \mathrm{B}$. +It is very likely that a number $n$ has at least one prime factor $p$ such that $p - 1$ is $\mathrm{B}$**-powersmooth** for small $\mathrm{B}$. An integer $m$ is said to be $\mathrm{B}$-powersmooth if every prime power dividing $m$ is at most $\mathrm{B}$. Formally, let $\mathrm{B} \geqslant 1$ and let $m$ be any positive integer. Suppose the prime factorization of $m$ is $m = \prod {q_i}^{e_i}$, where each $q_i$ is a prime and $e_i \geqslant 1$. Then $m$ is $\mathrm{B}$-powersmooth if, for all $i$, ${q_i}^{e_i} \leqslant \mathrm{B}$. E.g. the prime factorization of $4817191$ is $1303 \cdot 3697$. -And the factors are $31$-powersmooth and $16$-powersmooth respectably, because $1303 - 1 = 2 \cdot 3 \cdot 7 \cdot 31$ and $3697 - 1 = 2^4 \cdot 3 \cdot 7 \cdot 11$. -In 1974 John Pollard invented a method to extracts $B$-powersmooth factors from a composite number. +And the values, $1303 - 1$ and $3697 - 1$, are $31$-powersmooth and $16$-powersmooth respectively, because $1303 - 1 = 2 \cdot 3 \cdot 7 \cdot 31$ and $3697 - 1 = 2^4 \cdot 3 \cdot 7 \cdot 11$. +In 1974 John Pollard invented a method to extracts $\mathrm{B}$-powersmooth factors from a composite number. The idea comes from [Fermat's little theorem](phi-function.md#application). Let a factorization of $n$ be $n = p \cdot q$. @@ -180,7 +179,7 @@ This means that $a^M - 1 = p \cdot r$, and because of that also $p ~|~ \gcd(a^M Therefore, if $p - 1$ for a factor $p$ of $n$ divides $M$, we can extract a factor using [Euclid's algorithm](euclid-algorithm.md). -It is clear, that the smallest $M$ that is a multiple of every $B$-powersmooth number is $\text{lcm}(1,~2~,3~,4~,~\dots,~B)$. +It is clear, that the smallest $M$ that is a multiple of every $\mathrm{B}$-powersmooth number is $\text{lcm}(1,~2~,3~,4~,~\dots,~B)$. Or alternatively: $$M = \prod_{\text{prime } q \le B} q^{\lfloor \log_q B \rfloor}$$ @@ -189,11 +188,11 @@ Notice, if $p-1$ divides $M$ for all prime factors $p$ of $n$, then $\gcd(a^M - In this case we don't receive a factor. Therefore, we will try to perform the $\gcd$ multiple times, while we compute $M$. -Some composite numbers don't have $B$-powersmooth factors for small $B$. +Some composite numbers don't have $\mathrm{B}$-powersmooth factors for small $\mathrm{B}$. For example, the factors of the composite number $100~000~000~000~000~493 = 763~013 \cdot 131~059~365~961$ are $190~753$-powersmooth and $1~092~161~383$-powersmooth. We will have to choose $B >= 190~753$ to factorize the number. -In the following implementation we start with $B = 10$ and increase $B$ after each each iteration. +In the following implementation we start with $\mathrm{B} = 10$ and increase $\mathrm{B}$ after each each iteration. ```{.cpp file=factorization_p_minus_1} long long pollards_p_minus_1(long long n) { From bb7e13757ec14e867b3cd4de3da8966d87417270 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Sat, 24 May 2025 20:58:13 +0200 Subject: [PATCH 44/86] fix #1372 --- src/string/manacher.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string/manacher.md b/src/string/manacher.md index 0c8bd5928..26589b83c 100644 --- a/src/string/manacher.md +++ b/src/string/manacher.md @@ -147,7 +147,7 @@ vector manacher_odd(string s) { vector p(n + 2); int l = 0, r = 1; for(int i = 1; i <= n; i++) { - p[i] = max(0, min(r - i, p[l + (r - i)])); + p[i] = min(r - i, p[l + (r - i)]); while(s[i - p[i]] == s[i + p[i]]) { p[i]++; } From 2597e0558304678a7fa7f92c66a19f9f7913c974 Mon Sep 17 00:00:00 2001 From: t0wbo2t <52655804+t0wbo2t@users.noreply.github.com> Date: Thu, 29 May 2025 11:19:43 +0530 Subject: [PATCH 45/86] Update src/algebra/factorization.md Co-authored-by: Oleksandr Kulkov --- src/algebra/factorization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algebra/factorization.md b/src/algebra/factorization.md index 84bdd356d..bc606607f 100644 --- a/src/algebra/factorization.md +++ b/src/algebra/factorization.md @@ -188,8 +188,8 @@ Notice, if $p-1$ divides $M$ for all prime factors $p$ of $n$, then $\gcd(a^M - In this case we don't receive a factor. Therefore, we will try to perform the $\gcd$ multiple times, while we compute $M$. -Some composite numbers don't have $\mathrm{B}$-powersmooth factors for small $\mathrm{B}$. -For example, the factors of the composite number $100~000~000~000~000~493 = 763~013 \cdot 131~059~365~961$ are $190~753$-powersmooth and $1~092~161~383$-powersmooth. +Some composite numbers don't have factors $p$ s.t. $p-1$ is $\mathrm{B}$-powersmooth for small $\mathrm{B}$. +For example, for the composite number $100~000~000~000~000~493 = 763~013 \cdot 131~059~365~961$, values $p-1$ are $190~753$-powersmooth and $1~092~161~383$-powersmooth correspondingly. We will have to choose $B >= 190~753$ to factorize the number. In the following implementation we start with $\mathrm{B} = 10$ and increase $\mathrm{B}$ after each each iteration. From 54fec62526c6454ecd43b38544c6a56880031544 Mon Sep 17 00:00:00 2001 From: t0wbo2t <52655804+t0wbo2t@users.noreply.github.com> Date: Thu, 29 May 2025 11:19:54 +0530 Subject: [PATCH 46/86] Update src/algebra/factorization.md Co-authored-by: Oleksandr Kulkov --- src/algebra/factorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/factorization.md b/src/algebra/factorization.md index bc606607f..9d9ab7ed7 100644 --- a/src/algebra/factorization.md +++ b/src/algebra/factorization.md @@ -162,7 +162,7 @@ By looking at the squares $a^2$ modulo a fixed small number, it can be observed It is very likely that a number $n$ has at least one prime factor $p$ such that $p - 1$ is $\mathrm{B}$**-powersmooth** for small $\mathrm{B}$. An integer $m$ is said to be $\mathrm{B}$-powersmooth if every prime power dividing $m$ is at most $\mathrm{B}$. Formally, let $\mathrm{B} \geqslant 1$ and let $m$ be any positive integer. Suppose the prime factorization of $m$ is $m = \prod {q_i}^{e_i}$, where each $q_i$ is a prime and $e_i \geqslant 1$. Then $m$ is $\mathrm{B}$-powersmooth if, for all $i$, ${q_i}^{e_i} \leqslant \mathrm{B}$. E.g. the prime factorization of $4817191$ is $1303 \cdot 3697$. And the values, $1303 - 1$ and $3697 - 1$, are $31$-powersmooth and $16$-powersmooth respectively, because $1303 - 1 = 2 \cdot 3 \cdot 7 \cdot 31$ and $3697 - 1 = 2^4 \cdot 3 \cdot 7 \cdot 11$. -In 1974 John Pollard invented a method to extracts $\mathrm{B}$-powersmooth factors from a composite number. +In 1974 John Pollard invented a method to extract factors $p$, s.t. $p-1$ is $\mathrm{B}$-powersmooth, from a composite number. The idea comes from [Fermat's little theorem](phi-function.md#application). Let a factorization of $n$ be $n = p \cdot q$. From 53639d500284ae160ca2e9f968957c360b6f2040 Mon Sep 17 00:00:00 2001 From: t0wbo2t <52655804+t0wbo2t@users.noreply.github.com> Date: Thu, 29 May 2025 11:20:00 +0530 Subject: [PATCH 47/86] Update src/algebra/factorization.md Co-authored-by: Oleksandr Kulkov --- src/algebra/factorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/factorization.md b/src/algebra/factorization.md index 9d9ab7ed7..14715605f 100644 --- a/src/algebra/factorization.md +++ b/src/algebra/factorization.md @@ -190,7 +190,7 @@ Therefore, we will try to perform the $\gcd$ multiple times, while we compute $M Some composite numbers don't have factors $p$ s.t. $p-1$ is $\mathrm{B}$-powersmooth for small $\mathrm{B}$. For example, for the composite number $100~000~000~000~000~493 = 763~013 \cdot 131~059~365~961$, values $p-1$ are $190~753$-powersmooth and $1~092~161~383$-powersmooth correspondingly. -We will have to choose $B >= 190~753$ to factorize the number. +We will have to choose $B \geq 190~753$ to factorize the number. In the following implementation we start with $\mathrm{B} = 10$ and increase $\mathrm{B}$ after each each iteration. From ecf52f787a50ce378f335081cf8b0782dacbd19f Mon Sep 17 00:00:00 2001 From: Tushar Bisht <107390942+Tushar0009@users.noreply.github.com> Date: Sun, 1 Jun 2025 05:05:19 +0530 Subject: [PATCH 48/86] Update stack_queue_modification.md Added new Problem fron CSES Problem Set --- src/data_structures/stack_queue_modification.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data_structures/stack_queue_modification.md b/src/data_structures/stack_queue_modification.md index c8bee7927..fbce47929 100644 --- a/src/data_structures/stack_queue_modification.md +++ b/src/data_structures/stack_queue_modification.md @@ -187,5 +187,6 @@ Since all operations with the queue are performed in constant time on average, t ## Practice Problems * [Queries with Fixed Length](https://www.hackerrank.com/challenges/queries-with-fixed-length/problem) +* [Sliding Window Minimum](https://cses.fi/problemset/task/3221) * [Binary Land](https://www.codechef.com/MAY20A/problems/BINLAND) From cee3e33f380435e893ac8b8c20868e4c964e80eb Mon Sep 17 00:00:00 2001 From: This-is-Adroit <167745134+This-is-Adroit@users.noreply.github.com> Date: Sun, 8 Jun 2025 10:40:58 +0530 Subject: [PATCH 49/86] Update fixed_length_paths.md --- src/graph/fixed_length_paths.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/fixed_length_paths.md b/src/graph/fixed_length_paths.md index 9e1c1efad..66961bcba 100644 --- a/src/graph/fixed_length_paths.md +++ b/src/graph/fixed_length_paths.md @@ -63,7 +63,7 @@ Then the following formula computes each entry of $L_{k+1}$: $$L_{k+1}[i][j] = \min_{p = 1 \ldots n} \left(L_k[i][p] + G[p][j]\right)$$ When looking closer at this formula, we can draw an analogy with the matrix multiplication: -in fact the matrix $L_k$ is multiplied by the matrix $G$, the only difference is that instead in the multiplication operation we take the minimum instead of the sum. +in fact the matrix $L_k$ is multiplied by the matrix $G$, the only difference is that instead in the multiplication operation we take the minimum of the sum. $$L_{k+1} = L_k \odot G,$$ From 06625c22c38268c36e4a939cc264ae966bc6b968 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Sat, 14 Jun 2025 12:11:52 +0200 Subject: [PATCH 50/86] Update src/graph/fixed_length_paths.md --- src/graph/fixed_length_paths.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/fixed_length_paths.md b/src/graph/fixed_length_paths.md index 66961bcba..fd3810f9a 100644 --- a/src/graph/fixed_length_paths.md +++ b/src/graph/fixed_length_paths.md @@ -63,7 +63,7 @@ Then the following formula computes each entry of $L_{k+1}$: $$L_{k+1}[i][j] = \min_{p = 1 \ldots n} \left(L_k[i][p] + G[p][j]\right)$$ When looking closer at this formula, we can draw an analogy with the matrix multiplication: -in fact the matrix $L_k$ is multiplied by the matrix $G$, the only difference is that instead in the multiplication operation we take the minimum of the sum. +in fact the matrix $L_k$ is multiplied by the matrix $G$, the only difference is that instead in the multiplication operation we take the minimum instead of the sum, and the sum instead of the multiplication as the inner operation. $$L_{k+1} = L_k \odot G,$$ From 77381f8733608ffe3f759ed3e2b73ca05d940191 Mon Sep 17 00:00:00 2001 From: Aleksandr Mishukhin <100044766+aleksmish@users.noreply.github.com> Date: Mon, 30 Jun 2025 22:15:08 +0300 Subject: [PATCH 51/86] fix typo Changed "an selected" to "a selected" --- src/graph/mst_prim.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/mst_prim.md b/src/graph/mst_prim.md index 21649f28d..8815a2630 100644 --- a/src/graph/mst_prim.md +++ b/src/graph/mst_prim.md @@ -147,7 +147,7 @@ void prim() { ``` The adjacency matrix `adj[][]` of size $n \times n$ stores the weights of the edges, and it uses the weight `INF` if there doesn't exist an edge between two vertices. -The algorithm uses two arrays: the flag `selected[]`, which indicates which vertices we already have selected, and the array `min_e[]` which stores the edge with minimal weight to an selected vertex for each not-yet-selected vertex (it stores the weight and the end vertex). +The algorithm uses two arrays: the flag `selected[]`, which indicates which vertices we already have selected, and the array `min_e[]` which stores the edge with minimal weight to a selected vertex for each not-yet-selected vertex (it stores the weight and the end vertex). The algorithm does $n$ steps, in each iteration the vertex with the smallest edge weight is selected, and the `min_e[]` of all other vertices gets updated. ### Sparse graphs: $O(m \log n)$ From 7c3273f50a194e42040f70c70dac63c738ea38bd Mon Sep 17 00:00:00 2001 From: yousvf <145223965+yousvf@users.noreply.github.com> Date: Thu, 3 Jul 2025 18:57:46 +0300 Subject: [PATCH 52/86] Update treap.md it children --> its children --- src/data_structures/treap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_structures/treap.md b/src/data_structures/treap.md index 05eeb4bca..11ff00482 100644 --- a/src/data_structures/treap.md +++ b/src/data_structures/treap.md @@ -92,7 +92,7 @@ Alternatively, insert can be done by splitting the initial treap on $X$ and doin -Implementation of **Erase ($X$)** is also clear. First we descend in the tree (as in a regular binary search tree by $X$), looking for the element we want to delete. Once the node is found, we call **Merge** on it children and put the return value of the operation in the place of the element we're deleting. +Implementation of **Erase ($X$)** is also clear. First we descend in the tree (as in a regular binary search tree by $X$), looking for the element we want to delete. Once the node is found, we call **Merge** on its children and put the return value of the operation in the place of the element we're deleting. Alternatively, we can factor out the subtree holding $X$ with $2$ split operations and merge the remaining treaps (see the picture). From 88693011070023f665bbe87a0d43cdf4ef910ba0 Mon Sep 17 00:00:00 2001 From: AYUSH KUMAR TIWARI <139953157+ayushkrtiwari@users.noreply.github.com> Date: Sat, 12 Jul 2025 20:41:52 +0530 Subject: [PATCH 53/86] Grammatical Error Removed --- src/algebra/big-integer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/big-integer.md b/src/algebra/big-integer.md index 7f8dd1816..72d137983 100644 --- a/src/algebra/big-integer.md +++ b/src/algebra/big-integer.md @@ -30,7 +30,7 @@ To improve performance we'll use $10^9$ as the base, so that each "digit" of the const int base = 1000*1000*1000; ``` -Digits will be stored in order from least to most significant. All operations will be implemented so that after each of them the result doesn't have any leading zeros, as long as operands didn't have any leading zeros either. All operations which might result in a number with leading zeros should be followed by code which removes them. Note that in this representation there are two valid notations for number zero: and empty vector, and a vector with a single zero digit. +Digits will be stored in order from least to most significant. All operations will be implemented so that after each of them the result doesn't have any leading zeros, as long as operands didn't have any leading zeros either. All operations which might result in a number with leading zeros should be followed by code which removes them. Note that in this representation there are two valid notations for number zero: an empty vector, and a vector with a single zero digit. ### Output From 3abb392929688b2c7513ce6f7f823a7199593131 Mon Sep 17 00:00:00 2001 From: Kartik Laheri <20bce139@nirmauni.ac.in> Date: Sun, 13 Jul 2025 00:56:38 +0530 Subject: [PATCH 54/86] Patch fix in Manhattan Distance. --- src/geometry/manhattan-mst-sweep-line-1.png | Bin 85072 -> 63728 bytes src/geometry/manhattan-mst-sweep-line-2.png | Bin 69362 -> 52205 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/geometry/manhattan-mst-sweep-line-1.png b/src/geometry/manhattan-mst-sweep-line-1.png index 548f9c3524dd4b6bdff19a656f719679d5f33d15..a0f15e7d8487505215f09d52b809de13e3dab67e 100644 GIT binary patch literal 63728 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

I44K{YkR+fC-KATFy-t_&o3f5&eA52S# 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 Hu?+iPt8@Mx diff --git a/src/geometry/manhattan-mst-sweep-line-2.png b/src/geometry/manhattan-mst-sweep-line-2.png index 1fc349548db9196eead3e73065ec8db03d5e3264..599e2cd16ae532a2a0d2b5ea1a34a0588e33f722 100644 GIT binary patch literal 52205 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 literal 69362 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�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 F{{cfg`t1M! From 55e4d52b5710ea100661f68cf1068e482cc68b1d Mon Sep 17 00:00:00 2001 From: Abanoub Ashraf <92957180+abanoubashraf686@users.noreply.github.com> Date: Sat, 26 Jul 2025 23:01:08 +0300 Subject: [PATCH 55/86] =?UTF-8?q?docs:=20fix=20bridge=20count=20wording=20?= =?UTF-8?q?to=20=E2=80=9Cone=20or=20more=E2=80=9D=20in=20bridge-searching-?= =?UTF-8?q?online.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original text stated that the number of bridges decreases by “two or more,” which is incorrect in some cases. For example, in this graph: 1-2-3-1 3-4 4-5-6-4 There is one bridge (3–4). Adding an edge between 1 and 4 removes only that single bridge. This change updates the text to say “one or more,” which is accurate in all cases. --- src/graph/bridge-searching-online.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/bridge-searching-online.md b/src/graph/bridge-searching-online.md index 80ed25ead..1169fc146 100644 --- a/src/graph/bridge-searching-online.md +++ b/src/graph/bridge-searching-online.md @@ -57,7 +57,7 @@ When adding the next edge $(a, b)$ there can occur three situations: In this case, this edge forms a cycle along with some of the old bridges. All these bridges end being bridges, and the resulting cycle must be compressed into a new 2-edge-connected component. - Thus, in this case the number of bridges decreases by two or more. + Thus, in this case the number of bridges decreases by one or more. Consequently the whole task is reduced to the effective implementation of all these operations over the forest of 2-edge-connected components. From b455f1cea4ef43508985bb4667c1f4ef49fc7dd0 Mon Sep 17 00:00:00 2001 From: Arjun Patel <45395213+arjunUpatel@users.noreply.github.com> Date: Sun, 27 Jul 2025 02:10:49 -0400 Subject: [PATCH 56/86] Fix grammar in binary-exp.md an unit -> a unit. While the word unit starts with a 'u', the sound made pronounced is actually the of a consonant. Other phrases with similar properties include "a university" and "a unicorn". --- src/algebra/binary-exp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/binary-exp.md b/src/algebra/binary-exp.md index 52dfd27a5..99c12a30a 100644 --- a/src/algebra/binary-exp.md +++ b/src/algebra/binary-exp.md @@ -177,7 +177,7 @@ a_{31} & a_ {32} & a_ {33} & a_ {34} \\ a_{41} & a_ {42} & a_ {43} & a_ {44} \end{pmatrix}$$ -that, when multiplied by a vector with the old coordinates and an unit gives a new vector with the new coordinates and an unit: +that, when multiplied by a vector with the old coordinates and a unit gives a new vector with the new coordinates and a unit: $$\begin{pmatrix} x & y & z & 1 \end{pmatrix} \cdot \begin{pmatrix} From 410ce4b9214321db69fb57b60777cf54928dc20e Mon Sep 17 00:00:00 2001 From: Max <103229540+mlatysh199@users.noreply.github.com> Date: Mon, 28 Jul 2025 19:26:09 -0600 Subject: [PATCH 57/86] Update chinese-remainder-theorem.md --- src/algebra/chinese-remainder-theorem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/chinese-remainder-theorem.md b/src/algebra/chinese-remainder-theorem.md index dfbdbd840..5fb6b73fe 100644 --- a/src/algebra/chinese-remainder-theorem.md +++ b/src/algebra/chinese-remainder-theorem.md @@ -154,7 +154,7 @@ $$\left\{\begin{align} a & \equiv 2 \pmod{6} \end{align}\right.$$ -It is pretty simple to determine is a system has a solution. +It is pretty simple to determine if a system has a solution. And if it has one, we can use the original algorithm to solve a slightly modified system of congruences. A single congruence $a \equiv a_i \pmod{m_i}$ is equivalent to the system of congruences $a \equiv a_i \pmod{p_j^{n_j}}$ where $p_1^{n_1} p_2^{n_2}\cdots p_k^{n_k}$ is the prime factorization of $m_i$. From 276b929f62bc6c88810486da4565082b9b2a8d83 Mon Sep 17 00:00:00 2001 From: yousvf <145223965+yousvf@users.noreply.github.com> Date: Thu, 31 Jul 2025 11:48:33 +0300 Subject: [PATCH 58/86] Update linear-system-gauss.md --- src/linear_algebra/linear-system-gauss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linear_algebra/linear-system-gauss.md b/src/linear_algebra/linear-system-gauss.md index 503a93b1f..ed05b5cf9 100644 --- a/src/linear_algebra/linear-system-gauss.md +++ b/src/linear_algebra/linear-system-gauss.md @@ -42,7 +42,7 @@ Strictly speaking, the method described below should be called "Gauss-Jordan", o The algorithm is a `sequential elimination` of the variables in each equation, until each equation will have only one remaining variable. If $n = m$, you can think of it as transforming the matrix $A$ to identity matrix, and solve the equation in this obvious case, where solution is unique and is equal to coefficient $b_i$. -Gaussian elimination is based on two simple transformation: +Gaussian elimination is based on two simple transformations: * It is possible to exchange two equations * Any equation can be replaced by a linear combination of that row (with non-zero coefficient), and some other rows (with arbitrary coefficients). From 9c7b6a6a4a11673b13fc0b4fd36760773729a81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B3=D0=BE=D1=80=20=D0=A4=D0=B5=D1=84=D0=B8=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= <116756626+Gemefoll@users.noreply.github.com> Date: Thu, 7 Aug 2025 11:04:38 +0500 Subject: [PATCH 59/86] Update polynomial.md --- src/algebra/polynomial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/polynomial.md b/src/algebra/polynomial.md index cd0de655f..b9baa9858 100644 --- a/src/algebra/polynomial.md +++ b/src/algebra/polynomial.md @@ -192,7 +192,7 @@ This algorithm was mentioned in [Schönhage's article](http://algo.inria.fr/semi $$A^{-1}(x) \equiv \frac{1}{A(x)} \equiv \frac{A(-x)}{A(x)A(-x)} \equiv \frac{A(-x)}{T(x^2)} \pmod{x^k}$$ -Note that $T(x)$ can be computed with a single multiplication, after which we're only interested in the first half of coefficients of its inverse series. This effectively reduces the initial problem of computing $A^{-1} \pmod{x^k}$ to computing $T^{-1} \pmod{x^{\lfloor k / 2 \rfloor}}$. +Note that $T(x)$ can be computed with a single multiplication, after which we're only interested in the first half of coefficients of its inverse series. This effectively reduces the initial problem of computing $A^{-1} \pmod{x^k}$ to computing $T^{-1} \pmod{x^{\lceil k / 2 \rceil}}$. The complexity of this method can be estimated as From 61dd11ea7b42b0952f59f8e197dce50c2a7172dc Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Fri, 8 Aug 2025 09:42:56 +0200 Subject: [PATCH 60/86] Add links to the Discord server (#1493) --- README.md | 1 + mkdocs.yml | 5 +++++ src/overrides/partials/header.html | 16 ++++++++++------ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 513e55f32..445039e5a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Compiled pages are published at [https://cp-algorithms.com/](https://cp-algorith ## Changelog +- August, 2025: Launched a [Discord server](https://discord.gg/HZ5AecN3KX)! - October, 2024: Welcome new maintainers: [jxu](https://github.com/jxu), [mhayter](https://github.com/mhayter) and [kostero](https://github.com/kostero)! - October, 15, 2024: GitHub pages based mirror is now served at [https://gh.cp-algorithms.com/](https://gh.cp-algorithms.com/), and an auxiliary competitive programming library is available at [https://lib.cp-algorithms.com/](https://lib.cp-algorithms.com/). - July 16, 2024: Major overhaul of the [Finding strongly connected components / Building condensation graph](https://cp-algorithms.com/graph/strongly-connected-components.html) article. diff --git a/mkdocs.yml b/mkdocs.yml index 466463564..8dcdcc5f6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -79,6 +79,11 @@ plugins: - rss extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/cp-algorithms/cp-algorithms + - icon: fontawesome/brands/discord + link: https://discord.gg/HZ5AecN3KX analytics: provider: google property: G-7FLS2HCYHH diff --git a/src/overrides/partials/header.html b/src/overrides/partials/header.html index 967330642..0b6058769 100644 --- a/src/overrides/partials/header.html +++ b/src/overrides/partials/header.html @@ -87,14 +87,18 @@

- - - {% endif %} + {% if "navigation.tabs.sticky" in features %} {% if "navigation.tabs" in features %} From 6bc8214e43c26e02872a54d3fb5d93d9769eafd9 Mon Sep 17 00:00:00 2001 From: Syed Umair <126373476+syed0369@users.noreply.github.com> Date: Sat, 9 Aug 2025 14:35:50 +0530 Subject: [PATCH 61/86] Fix formula for r*a = C solution (#1479) --- src/geometry/basic-geometry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/basic-geometry.md b/src/geometry/basic-geometry.md index 89acb1642..afd44b315 100644 --- a/src/geometry/basic-geometry.md +++ b/src/geometry/basic-geometry.md @@ -180,7 +180,7 @@ double angle(point2d a, point2d b) { ``` To see the next important property we should take a look at the set of points $\mathbf r$ for which $\mathbf r\cdot \mathbf a = C$ for some fixed constant $C$. -You can see that this set of points is exactly the set of points for which the projection onto $\mathbf a$ is the point $C \cdot \dfrac{\mathbf a}{|\mathbf a|}$ and they form a hyperplane orthogonal to $\mathbf a$. +You can see that this set of points is exactly the set of points for which the projection onto $\mathbf a$ is the point $C \cdot \dfrac{\mathbf a}{|\mathbf a| ^ 2}$ and they form a hyperplane orthogonal to $\mathbf a$. You can see the vector $\mathbf a$ alongside with several such vectors having same dot product with it in 2D on the picture below:
From e8e30225738e4d68b78af1a424e3d68dc2cf91a5 Mon Sep 17 00:00:00 2001 From: Deepank Tyagi <90136390+DeepankTyagi2001@users.noreply.github.com> Date: Sat, 9 Aug 2025 14:40:30 +0530 Subject: [PATCH 62/86] Fix grammar: add missing 'is' in website text (#1482) Corrected a grammatical error by adding the missing verb 'is' in the website content. This ensures proper sentence structure and improves readability. --- src/data_structures/stack_queue_modification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_structures/stack_queue_modification.md b/src/data_structures/stack_queue_modification.md index fbce47929..5fad2021c 100644 --- a/src/data_structures/stack_queue_modification.md +++ b/src/data_structures/stack_queue_modification.md @@ -11,7 +11,7 @@ first we will modify a stack in a way that allows us to find the smallest elemen ## Stack modification -We want to modify the stack data structure in such a way, that it possible to find the smallest element in the stack in $O(1)$ time, while maintaining the same asymptotic behavior for adding and removing elements from the stack. +We want to modify the stack data structure in such a way, that it is possible to find the smallest element in the stack in $O(1)$ time, while maintaining the same asymptotic behavior for adding and removing elements from the stack. Quick reminder, on a stack we only add and remove elements on one end. To do this, we will not only store the elements in the stack, but we will store them in pairs: the element itself and the minimum in the stack starting from this element and below. From 742db16537094be3b59f25a9eedf9669518f60ef Mon Sep 17 00:00:00 2001 From: Shoot <11522779+Shoot@users.noreply.github.com> Date: Mon, 11 Aug 2025 11:42:20 +0300 Subject: [PATCH 63/86] Update manhattan-distance.md (#1490) Transformation \alpha was wrong, because it should just Quote: rotation of the plane followed by a dilation about a center Wrong transformation: (x=1,y=100) -> (x'=101, y'=-99) (wrong transformation is 135 degrees clockwise in this case, not 45), Correct transformation: (x=1,y=100) -> (x'=101, y'=99) Basically, I removed reflection over line x --- src/geometry/manhattan-distance.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/geometry/manhattan-distance.md b/src/geometry/manhattan-distance.md index 87514868a..86e1d0485 100644 --- a/src/geometry/manhattan-distance.md +++ b/src/geometry/manhattan-distance.md @@ -67,11 +67,11 @@ To prove this, we just need to analyze the signs of $m$ and $n$. And it's left a We may apply this equation to the Manhattan distance formula to find out that -$$d((x_1, y_1), (x_2, y_2)) = |x_1 - x_2| + |y_1 - y_2| = \text{max}(|(x_1 + y_1) - (x_2 + y_2)|, |(x_1 - y_1) - (x_2 - y_2)|).$$ +$$d((x_1, y_1), (x_2, y_2)) = |x_1 - x_2| + |y_1 - y_2| = \text{max}(|(x_1 + y_1) - (x_2 + y_2)|, |(y_1 - x_1) - (y_2 - x_2)|).$$ -The last expression in the previous equation is the [Chebyshev distance](https://en.wikipedia.org/wiki/Chebyshev_distance) of the points $(x_1 + y_1, x_1 - y_1)$ and $(x_2 + y_2, x_2 - y_2)$. This means that, after applying the transformation +The last expression in the previous equation is the [Chebyshev distance](https://en.wikipedia.org/wiki/Chebyshev_distance) of the points $(x_1 + y_1, y_1 - x_1)$ and $(x_2 + y_2, y_2 - x_2)$. This means that, after applying the transformation -$$\alpha : (x, y) \to (x + y, x - y),$$ +$$\alpha : (x, y) \to (x + y, y - x),$$ the Manhattan distance between the points $p$ and $q$ turns into the Chebyshev distance between $\alpha(p)$ and $\alpha(q)$. From 8668f0a99d0aba632abd10fe701d8ee693a839ef Mon Sep 17 00:00:00 2001 From: Arjun Patel <45395213+arjunUpatel@users.noreply.github.com> Date: Fri, 15 Aug 2025 17:04:35 -0400 Subject: [PATCH 64/86] Fix grammar error in linear-diophantine-equation.md --- src/algebra/linear-diophantine-equation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/linear-diophantine-equation.md b/src/algebra/linear-diophantine-equation.md index 3f4ede86c..d70d19d26 100644 --- a/src/algebra/linear-diophantine-equation.md +++ b/src/algebra/linear-diophantine-equation.md @@ -63,7 +63,7 @@ $$a x_g + b y_g = g$$ If $c$ is divisible by $g = \gcd(a, b)$, then the given Diophantine equation has a solution, otherwise it does not have any solution. The proof is straight-forward: a linear combination of two numbers is divisible by their common divisor. -Now supposed that $c$ is divisible by $g$, then we have: +Now suppose that $c$ is divisible by $g$, then we have: $$a \cdot x_g \cdot \frac{c}{g} + b \cdot y_g \cdot \frac{c}{g} = c$$ From 50bb121f244f4053a26f21950df5471f3d22ddc4 Mon Sep 17 00:00:00 2001 From: AYUSH KUMAR TIWARI <139953157+ayushkrtiwari@users.noreply.github.com> Date: Sun, 17 Aug 2025 23:25:13 +0530 Subject: [PATCH 65/86] Additional Problems on Burnside Lemma --- src/combinatorics/burnside.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/combinatorics/burnside.md b/src/combinatorics/burnside.md index 894b1e87d..87a8540a0 100644 --- a/src/combinatorics/burnside.md +++ b/src/combinatorics/burnside.md @@ -271,3 +271,12 @@ int solve(int n, int m) { * [CSES - Counting Grids](https://cses.fi/problemset/task/2210) * [Codeforces - Buildings](https://codeforces.com/gym/101873/problem/B) * [CS Academy - Cube Coloring](https://csacademy.com/contest/beta-round-8/task/cube-coloring/) +* [Codeforces - Side Transmutations](https://codeforces.com/contest/1065/problem/E) +* [LightOJ - Necklace](https://vjudge.net/problem/LightOJ-1419) +* [POJ - Necklace of Beads](http://poj.org/problem?id=1286) +* [CodeChef - Lucy and Flowers](https://www.codechef.com/problems/DECORATE) +* [HackerRank - Count the Necklaces](https://www.hackerrank.com/contests/infinitum12/challenges/count-the-necklaces) +* [POJ - Magic Bracelet](http://poj.org/problem?id=2888) +* [SPOJ - Sorting Machine](https://www.spoj.com/problems/SRTMACH/) +* [Project Euler - Pizza Toppings](https://projecteuler.net/problem=281) +* [ICPC 2011 SERCP - Alphabet Soup](https://archive.algo.is/icpc/swerc/2011/SWERC-set.pdf) \ No newline at end of file From 8f8fbbcc08be8218a30ba6df14ef9fcafeb2b4a4 Mon Sep 17 00:00:00 2001 From: AYUSH KUMAR TIWARI <139953157+ayushkrtiwari@users.noreply.github.com> Date: Mon, 18 Aug 2025 00:48:12 +0530 Subject: [PATCH 66/86] updated problem link icpc 2011 problem pdf replaced with practice link --- src/combinatorics/burnside.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/combinatorics/burnside.md b/src/combinatorics/burnside.md index 87a8540a0..5479c3703 100644 --- a/src/combinatorics/burnside.md +++ b/src/combinatorics/burnside.md @@ -279,4 +279,4 @@ int solve(int n, int m) { * [POJ - Magic Bracelet](http://poj.org/problem?id=2888) * [SPOJ - Sorting Machine](https://www.spoj.com/problems/SRTMACH/) * [Project Euler - Pizza Toppings](https://projecteuler.net/problem=281) -* [ICPC 2011 SERCP - Alphabet Soup](https://archive.algo.is/icpc/swerc/2011/SWERC-set.pdf) \ No newline at end of file +* [ICPC 2011 SERCP - Alphabet Soup](https://basecamp.eolymp.com/tr/problems/3064) From ed3350504dc05db0abc96255b450e445912b3d38 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Tue, 19 Aug 2025 17:59:22 +0200 Subject: [PATCH 67/86] Add minimum enclosing circle article (#1498) New original article --- README.md | 1 + src/geometry/enclosing-circle.md | 209 +++++++++++++++++++++++++++++++ src/navigation.md | 1 + 3 files changed, 211 insertions(+) create mode 100644 src/geometry/enclosing-circle.md diff --git a/README.md b/README.md index 445039e5a..2c45bf67c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Compiled pages are published at [https://cp-algorithms.com/](https://cp-algorith ### New articles +- (19 August 2025) [Minimum Enclosing Circle](https://cp-algorithms.com/geometry/enclosing-circle.html) - (21 May 2025) [Simulated Annealing](https://cp-algorithms.com/num_methods/simulated_annealing.html) - (12 July 2024) [Manhattan distance](https://cp-algorithms.com/geometry/manhattan-distance.html) - (8 June 2024) [Knapsack Problem](https://cp-algorithms.com/dynamic_programming/knapsack.html) diff --git a/src/geometry/enclosing-circle.md b/src/geometry/enclosing-circle.md new file mode 100644 index 000000000..accef58e5 --- /dev/null +++ b/src/geometry/enclosing-circle.md @@ -0,0 +1,209 @@ +--- +tags: + - Original +--- + +# Minimum Enclosing Circle + +Consider the following problem: + +!!! example "[Library Checker - Minimum Enclosing Circle](https://judge.yosupo.jp/problem/minimum_enclosing_circle)" + + You're given $n \leq 10^5$ points $p_i=(x_i, y_i)$. + + For each $p_i$, find whether it lies on the circumference of the minimum enclosing circle of $\{p_1,\dots,p_n\}$. + +Here, by the minimum enclosing circle (MEC) we mean a circle with minimum possible radius that contains all the $n$ p, inside the circle or on its boundary. This problem has a simple randomized solution that, on first glance, looks like it would run in $O(n^3)$, but actually works in $O(n)$ expected time. + +To better understand the reasoning below, we should immediately note that the solution to the problem is unique: + +??? question "Why is the MEC unique?" + + Consider the following setup: Let $r$ be the radius of the MEC. We draw a circle of radius $r$ around each of the p $p_1,\dots,p_n$. Geometrically, the centers of circles that have radius $r$ and cover all the points $p_1,\dots,p_n$ form the intersection of all $n$ circles. + + Now, if the intersection is just a single point, this already proves that it is unique. Otherwise, the intersection is a shape of non-zero area, so we can reduce $r$ by a tiny bit, and still have non-empty intersection, which contradicts the assumption that $r$ was the minimum possible radius of the enclosing circle. + + With a similar logic, we can also show the uniqueness of the MEC if we additionally demand that it passes through a given specific point $p_i$ or two points $p_i$ and $p_j$ (it is also unique because its radius uniquely defines it). + + Alternatively, we can also assume that there are two MECs, and then notice that their intersection (which contains p $p_1,\dots,p_n$ already) must have a smaller diameter than initial circles, and thus can be covered with a smaller circle. + +## Welzl's algorithm + +For brevity, let's denote $\operatorname{mec}(p_1,\dots,p_n)$ to be the MEC of $\{p_1,\dots,p_n\}$, and let $P_i = \{p_1,\dots,p_i\}$. + +The algorithm, initially [proposed](https://doi.org/10.1007/BFb0038202) by Welzl in 1991, goes as follows: + +1. Apply a random permutation to the input sequence of points. +2. Maintain the current candidate to be the MEC $C$, starting with $C = \operatorname{mec}(p_1, p_2)$. +3. Iterate over $i=3..n$ and check if $p_i \in C$. + 1. If $p_i \in C$ it means that $C$ is the MEC of $P_i$. + 2. Otherwise, assign $C = \operatorname{mec}(p_i, p_1)$ and iterate over $j=2..i$ and check if $p_j \in C$. + 1. If $p_j \in C$, then $C$ is the MEC of $P_j$ among circles that pass through $p_i$. + 2. Otherwise, assign $C=\operatorname{mec}(p_i, p_j)$ and iterate over $k=1..j$ and check if $p_k \in C$. + 1. If $p_k \in C$, then $C$ is the MEC of $P_k$ among circles that pass through $p_i$ and $p_j$. + 2. Otherwise, $C=\operatorname{mec}(p_i,p_j,p_k)$ is the MEC of $P_k$ among circles that pass through $p_i$ and $p_j$. + +We can see that each level of nestedness here has an invariant to maintain (that $C$ is the MEC among circles that also pass through additionally given $0$, $1$ or $2$ points), and whenever the inner loop closes, its invariant becomes equivalent to the invariant of the current iteration of its parent loop. This, in turn, ensures the _correctness_ of the algorithm as a whole. + +Omitting some technical details, for now, the whole algorithm can be implemented in C++ as follows: + +```cpp +struct point {...}; + +// Is represented by 2 or 3 points on its circumference +struct mec {...}; + +bool inside(mec const& C, point p) { + return ...; +} + +// Choose some good generator of randomness for the shuffle +mt19937_64 gen(...); +mec enclosing_circle(vector &p) { + ranges::shuffle(p, gen); + auto C = mec{p[0], p[1]}; + for(int i = 0; i < n; i++) { + if(!inside(C, p[i])) { + C = mec{p[i], p[0]}; + for(int j = 0; j < i; j++) { + if(!inside(C, p[j])) { + C = mec{p[i], p[j]}; + for(int k = 0; k < j; k++) { + if(!inside(C, p[k])) { + C = mec{p[i], p[j], p[k]}; + } + } + } + } + } + } + return C; +} +``` + +Now, it is to be expected that checking that a point $p_i$ is inside the MEC of $2$ or $3$ points can be done in $O(1)$ (we will discuss this later on). But even then, the algorithm above looks as if it would take $O(n^3)$ in the worst case just because of all the nested loops. So, how come we claimed the linear expected runtime? Let's figure out! + +### Complexity analysis + +For the inner-most loop (over $k$), clearly its expected runtime is $O(j)$ operations. What about the loop over $j$? + +It only triggers the next loop if $p_j$ is on the boundary of the MEC of $P_j$ that also passes through point $i$, _and removing $p_j$ would further shrink the circle_. Of all points in $P_j$ there can only be at most $2$ points with such property, because if there are more than $2$ points from $P_j$ on the boundary, it means that after removing any of them, there will still be at least $3$ points on the boundary, sufficient to uniquely define the circle. + +In other words, after initial random shuffle, there is at most $\frac{2}{j}$ probability that we get one of the at most two unlucky points as $p_j$. Summing it up over all $j$ from $1$ to $i$, we get the expected runtime of + +$$ +\sum\limits_{j=1}^i \frac{2}{j} \cdot O(j) = O(i). +$$ + +In exactly same fashion we can now also prove that the outermost loop has expected runtime of $O(n)$. + +### Checking that a point is in the MEC of 2 or 3 points + +Let's now figure out the implementation detail of `point` and `mec`. In this problem, it turns out to be particularly useful to use [std::complex](https://codeforces.com/blog/entry/22175) as a class for points: + +```cpp +using ftype = int64_t; +using point = complex; +``` + +As a reminder, a complex number is a number of type $x+yi$, where $i^2=-1$ and $x, y \in \mathbb R$. In C++, such complex number is represented by a 2-dimensional point $(x, y)$. Complex numbers already implement basic component-wise linear operations (addition, multiplication by a real number), but also their multiplication and division carry certain geometric meaning. + +Without going in too much detail, we will note the most important property for this particular task: Multiplying two complex numbers adds up their polar angles (counted from $Ox$ counter-clockwise), and taking a conjugate (i.e. changing $z=x+yi$ into $\overline{z} = x-yi$) multiplies the polar angle with $-1$. This allows us to formulate some very simple criteria for whether a point $z$ is inside the MEC of $2$ or $3$ specific points. + +#### MEC of 2 points + +For $2$ points $a$ and $b$, their MEC is simply the circle centered at $\frac{a+b}{2}$ with the radius $\frac{|a-b|}{2}$, in other words the circle that has $ab$ as a diameter. To check if $z$ is inside this circle we simply need to check that the angle between $za$ and $zb$ is not acute. + +
+ +
+Inner angles are obtuse, external angles are acute and angles on the circumference are right +
+ +Equivalently, we need to check that + +$$ +I_0=(b-z)\overline{(a-z)} +$$ + +doesn't have a positive real coordinate (corresponding to points that have a polar angle between $-90^\circ$ and $90^\circ$). + +#### MEC of 3 points + +Adding $z$ to the triangle $abc$ will make it a quadrilateral. Consider the following expression: + +$$ +\angle azb + \angle bca +$$ + +In a [cyclic quadrilateral](https://en.wikipedia.org/wiki/Cyclic_quadrilateral), if $c$ and $z$ are from the same side of $ab$, then the angles are equal, and will ad up to $0^\circ$ when summed up signed (i.e. positive if counter-clockwise and negative if clockwise). Correspondingly, if $c$ and $z$ are on the opposite sides, the angles will add up to $180^\circ$. + +
+ +
+Adjacent inscribed angles are same, opposing angles complement to 180 degrees +
+ +In terms of complex numbers, we can note that $\angle azb$ is the polar angle of $(b-z)\overline{(a-z)}$ and $\angle bca$ is the polar angle of $(a-c)\overline{(b-c)}$. Thus, we can conclude that $\angle azb + \angle bca$ is the polar angle of + +$$ +I_1 = (b-z) \overline{(a-z)} (a-c) \overline{(b-c)} +$$ + +If the angle is $0^\circ$ or $180^\circ$, it means that the imaginary part of $I_1$ is $0$, otherwise we can deduce whether $z$ is inside or outside of the enclosing circle of $abc$ by checking the sign of the imaginary part of $I_1$. Positive imaginary part corresponds to positive angles, and negative imaginary part corresponds to negative angles. + +But which one of them means that $z$ is inside or outside of the circle? As we already noticed, having $z$ inside the circle generally increases the magnitude of $\angle azb$, while having it outside the circle decreases it. As such, we have the following 4 cases: + +1. $\angle bca > 0^\circ$, $c$ on the same side of $ab$ as $z$. Then, $\angle azb < 0^\circ$, and $\angle azb + \angle bca < 0^\circ$ for points inside the circle. +3. $\angle bca < 0^\circ$, $c$ on the same side of $ab$ as $z$. Then, $\angle azb > 0^\circ$, and $\angle azb + \angle bca > 0^\circ$ for points inside the circle. +2. $\angle bca > 0^\circ$, $c$ on the opposite side of $ab$ to $z$. Then, $\angle azb > 0^\circ$ and $\angle azb + \angle bca > 180^\circ$ for points inside the circle. +4. $\angle bca < 0^\circ$, $c$ on the opposite side of $ab$ to $z$. Then, $\angle azb < 0^\circ$ and $\angle azb + \angle bca < 180^\circ$ for points inside the circle. + +In other words, if $\angle bca$ is positive, points inside the circle will have $\angle azb + \angle bca < 0^\circ$, otherwise they will have $\angle azb + \angle bca > 0^\circ$, assuming that we normalize the angles between $-180^\circ$ and $180^\circ$. This, in turn, can be checked by the signs of imaginary parts of $I_2=(a-c)\overline{(b-c)}$ and $I_1 = I_0 I_2$. + +**Note**: As we multiply four complex numbers to get $I_1$, the intermediate coefficients can be as large as $O(A^4)$, where $A$ is the largest coordinate magnitude in the input. On the bright side, if the input is integer, both checks above can be done fully in integers. + +#### Implementation + +Now, to actually implement the check, we should first decide how to represent the MEC. As our criteria work with the points directly, a natural and efficient way to do this is to say that MEC is directly represented as a pair or triple of points that defines it: + +```cpp +using mec = variant< + array, + array +>; +``` + +Now, we can use `std::visit` to efficiently deal with both cases in accordance with criteria above: + +```cpp +/* I < 0 if z inside C, + I > 0 if z outside C, + I = 0 if z on the circumference of C */ +ftype indicator(mec const& C, point z) { + return visit([&](auto &&C) { + point a = C[0], b = C[1]; + point I0 = (b - z) * conj(a - z); + if constexpr (size(C) == 2) { + return real(I0); + } else { + point c = C[2]; + point I2 = (a - c) * conj(b - c); + point I1 = I0 * I2; + return imag(I2) < 0 ? -imag(I1) : imag(I1); + } + }, C); +} + +bool inside(mec const& C, point p) { + return indicator(C, p) <= 0; +} + +``` + +Now, we can finally ensure that everything works by submitting the problem to the Library Checker: [#308668](https://judge.yosupo.jp/submission/308668). + +## Practice problems + +- [Library Checker - Minimum Enclosing Circle](https://judge.yosupo.jp/problem/minimum_enclosing_circle) +- [BOI 2002 - Aliens](https://www.spoj.com/problems/ALIENS) \ No newline at end of file diff --git a/src/navigation.md b/src/navigation.md index 6b7caef53..b0ca42e24 100644 --- a/src/navigation.md +++ b/src/navigation.md @@ -145,6 +145,7 @@ search: - [Vertical decomposition](geometry/vertical_decomposition.md) - [Half-plane intersection - S&I Algorithm in O(N log N)](geometry/halfplane-intersection.md) - [Manhattan Distance](geometry/manhattan-distance.md) + - [Minimum Enclosing Circle](geometry/enclosing-circle.md) - Graphs - Graph traversal - [Breadth First Search](graph/breadth-first-search.md) From 878f8b42ea88a542908730dc8b79887af9bccd3a Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Tue, 19 Aug 2025 20:08:17 +0200 Subject: [PATCH 68/86] touch commit for gh.cp-algorithms.com From d2fa0f4b716b3f82ed509afa316236e5778e9193 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Tue, 19 Aug 2025 20:12:53 +0200 Subject: [PATCH 69/86] fix link to phi-function.md --- src/algebra/discrete-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebra/discrete-log.md b/src/algebra/discrete-log.md index dd899fb25..de93bdea7 100644 --- a/src/algebra/discrete-log.md +++ b/src/algebra/discrete-log.md @@ -129,7 +129,7 @@ With this change, the complexity of the algorithm is still the same, but now the Instead of a `map`, we can also use a hash table (`unordered_map` in C++) which has the average time complexity $O(1)$ for inserting and searching. Problems often ask for the minimum $x$ which satisfies the solution. -It is possible to get all answers and take the minimum, or reduce the first found answer using [Euler's theorem](phi-function.md#toc-tgt-2), but we can be smart about the order in which we calculate values and ensure the first answer we find is the minimum. +It is possible to get all answers and take the minimum, or reduce the first found answer using [Euler's theorem](phi-function.md#application), but we can be smart about the order in which we calculate values and ensure the first answer we find is the minimum. ```{.cpp file=discrete_log} // Returns minimum x for which a ^ x % m = b % m, a and m are coprime. From f00c1b4ee9950fb54343c516e7f733c652c48a32 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Tue, 19 Aug 2025 20:20:25 +0200 Subject: [PATCH 70/86] Fix hyperlink in image description --- src/num_methods/binary_search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index ae9b2aed1..b78e710bb 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -16,7 +16,7 @@ The most typical problem that leads to the binary search is as follows. You're g
Binary search of the value $7$ in an array.
-The image by [AlwaysAngry](https://commons.wikimedia.org/wiki/User:AlwaysAngry) is distributed under CC BY-SA 4.0 license. +The image by AlwaysAngry is distributed under CC BY-SA 4.0 license. Now assume that we know two indices $L < R$ such that $A_L \leq k \leq A_R$. Because the array is sorted, we can deduce that $k$ either occurs among $A_L, A_{L+1}, \dots, A_R$ or doesn't occur in the array at all. If we pick an arbitrary index $M$ such that $L < M < R$ and check whether $k$ is less or greater than $A_M$. We have two possible cases: From a0f92b2d71fbbe1174e46fa92d9bf44075aca544 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Sat, 23 Aug 2025 17:20:14 +0200 Subject: [PATCH 71/86] Solicit donations on the website (#1499) * Solicit donations on the website * Add donation bar warning * Less intrusive donation banner * default link color in donation banner * reduce HIDE_DAYS to 90 * Update changelog with donation system overhaul --------- Co-authored-by: Michael Hayter --- README.md | 1 + mkdocs.yml | 3 +++ src/javascript/donation-banner.js | 30 ++++++++++++++++++++++++ src/overrides/partials/header.html | 6 +++++ src/stylesheets/extra.css | 37 +++++++++++++++++++++++++++++- 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/javascript/donation-banner.js diff --git a/README.md b/README.md index 2c45bf67c..f2383c91d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Compiled pages are published at [https://cp-algorithms.com/](https://cp-algorith ## Changelog +- August, 2025: Overhaul of CP-Algorithms [donation system](https://github.com/sponsors/cp-algorithms). Please consider supporting us, so that we can grow! - August, 2025: Launched a [Discord server](https://discord.gg/HZ5AecN3KX)! - October, 2024: Welcome new maintainers: [jxu](https://github.com/jxu), [mhayter](https://github.com/mhayter) and [kostero](https://github.com/kostero)! - October, 15, 2024: GitHub pages based mirror is now served at [https://gh.cp-algorithms.com/](https://gh.cp-algorithms.com/), and an auxiliary competitive programming library is available at [https://lib.cp-algorithms.com/](https://lib.cp-algorithms.com/). diff --git a/mkdocs.yml b/mkdocs.yml index 8dcdcc5f6..f1b6fcbc6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -31,6 +31,7 @@ edit_uri: edit/main/src/ copyright: Text is available under the Creative Commons Attribution Share Alike 4.0 International License
Copyright © 2014 - 2025 by cp-algorithms contributors extra_javascript: - javascript/config.js + - javascript/donation-banner.js - https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6 - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js extra_css: @@ -84,6 +85,8 @@ extra: link: https://github.com/cp-algorithms/cp-algorithms - icon: fontawesome/brands/discord link: https://discord.gg/HZ5AecN3KX + - icon: fontawesome/solid/circle-dollar-to-slot + link: https://github.com/sponsors/cp-algorithms analytics: provider: google property: G-7FLS2HCYHH diff --git a/src/javascript/donation-banner.js b/src/javascript/donation-banner.js new file mode 100644 index 000000000..8c92268a5 --- /dev/null +++ b/src/javascript/donation-banner.js @@ -0,0 +1,30 @@ +document.addEventListener("DOMContentLoaded", () => { + const STORAGE_KEY = "donationBannerHiddenUntil"; + const HIDE_DAYS = 90; + + const hiddenUntil = Number(localStorage.getItem(STORAGE_KEY) || 0); + if (Date.now() < hiddenUntil) return; + + const banner = document.createElement("aside"); + banner.id = "donation-banner"; + banner.innerHTML = ` +
+

+ Please consider + + supporting us + — ad-free, volunteer-run. +

+ +
+ `; + + const content = document.querySelector("div.md-content") || document.body; + content.insertBefore(banner, content.firstChild); + + banner.querySelector(".donation-close").addEventListener("click", () => { + banner.remove(); + const until = Date.now() + HIDE_DAYS * 24 * 60 * 60 * 1000; + localStorage.setItem(STORAGE_KEY, String(until)); + }); +}); diff --git a/src/overrides/partials/header.html b/src/overrides/partials/header.html index 0b6058769..ab875aef1 100644 --- a/src/overrides/partials/header.html +++ b/src/overrides/partials/header.html @@ -99,6 +99,12 @@ {% include ".icons/fontawesome/brands/discord.svg" %}
+ + {% if "navigation.tabs.sticky" in features %} {% if "navigation.tabs" in features %} diff --git a/src/stylesheets/extra.css b/src/stylesheets/extra.css index d40c3e65f..b63b3c9a9 100644 --- a/src/stylesheets/extra.css +++ b/src/stylesheets/extra.css @@ -54,4 +54,39 @@ body[dir=rtl] .metadata.page-metadata .contributors-text{ .arithmatex{ overflow-y: hidden !important; -} \ No newline at end of file +} + +/* Donation banner */ +#donation-banner { + margin: 0.75rem 0.75rem 0; +} + +.donation-banner { + display: flex; + + background: #fff9c4; + border: 1px solid #f0e68c; + color: #2b2b2b; + + padding: 0.5rem 0.5rem; + border-radius: 8px; + font-size: 0.75rem; +} + +.donation-text { margin: 0; } +.donation-link { + color: revert; + text-decoration: underline; +} + +.donation-close { + margin-left: auto; + font-size: 1rem; + cursor: pointer; +} + +[data-md-color-scheme="slate"] .donation-banner { + background: #3b3200; + border-color: #665c1e; + color: #fff7b3; +} From 080d95f8ace5fa749dff0ec8103d440ad1458044 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Sat, 23 Aug 2025 23:26:37 +0200 Subject: [PATCH 72/86] Remove 'BOI 2002 - Aliens' from practice problems for consequent PR --- src/geometry/enclosing-circle.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/geometry/enclosing-circle.md b/src/geometry/enclosing-circle.md index accef58e5..61f8e66ec 100644 --- a/src/geometry/enclosing-circle.md +++ b/src/geometry/enclosing-circle.md @@ -206,4 +206,3 @@ Now, we can finally ensure that everything works by submitting the problem to th ## Practice problems - [Library Checker - Minimum Enclosing Circle](https://judge.yosupo.jp/problem/minimum_enclosing_circle) -- [BOI 2002 - Aliens](https://www.spoj.com/problems/ALIENS) \ No newline at end of file From 48bd1e1b5b3bdb9477255f6e1696036acae479d7 Mon Sep 17 00:00:00 2001 From: Dragos Ristache Date: Sat, 23 Aug 2025 18:03:07 -0400 Subject: [PATCH 73/86] New problem + typos (#1501) --- src/geometry/enclosing-circle.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/geometry/enclosing-circle.md b/src/geometry/enclosing-circle.md index 61f8e66ec..e943a2b85 100644 --- a/src/geometry/enclosing-circle.md +++ b/src/geometry/enclosing-circle.md @@ -13,19 +13,19 @@ Consider the following problem: For each $p_i$, find whether it lies on the circumference of the minimum enclosing circle of $\{p_1,\dots,p_n\}$. -Here, by the minimum enclosing circle (MEC) we mean a circle with minimum possible radius that contains all the $n$ p, inside the circle or on its boundary. This problem has a simple randomized solution that, on first glance, looks like it would run in $O(n^3)$, but actually works in $O(n)$ expected time. +Here, by the minimum enclosing circle (MEC) we mean a circle with minimum possible radius that contains all the $n$ points, inside the circle or on its boundary. This problem has a simple randomized solution that, on first glance, looks like it would run in $O(n^3)$, but actually works in $O(n)$ expected time. To better understand the reasoning below, we should immediately note that the solution to the problem is unique: ??? question "Why is the MEC unique?" - Consider the following setup: Let $r$ be the radius of the MEC. We draw a circle of radius $r$ around each of the p $p_1,\dots,p_n$. Geometrically, the centers of circles that have radius $r$ and cover all the points $p_1,\dots,p_n$ form the intersection of all $n$ circles. + Consider the following setup: Let $r$ be the radius of the MEC. We draw a circle of radius $r$ around each of the points $p_1,\dots,p_n$. Geometrically, the centers of circles that have radius $r$ and cover all the points $p_1,\dots,p_n$ form the intersection of all $n$ circles. Now, if the intersection is just a single point, this already proves that it is unique. Otherwise, the intersection is a shape of non-zero area, so we can reduce $r$ by a tiny bit, and still have non-empty intersection, which contradicts the assumption that $r$ was the minimum possible radius of the enclosing circle. With a similar logic, we can also show the uniqueness of the MEC if we additionally demand that it passes through a given specific point $p_i$ or two points $p_i$ and $p_j$ (it is also unique because its radius uniquely defines it). - Alternatively, we can also assume that there are two MECs, and then notice that their intersection (which contains p $p_1,\dots,p_n$ already) must have a smaller diameter than initial circles, and thus can be covered with a smaller circle. + Alternatively, we can also assume that there are two MECs, and then notice that their intersection (which contains the points $p_1,\dots,p_n$ already) must have a smaller diameter than initial circles, and thus can be covered with a smaller circle. ## Welzl's algorithm @@ -206,3 +206,4 @@ Now, we can finally ensure that everything works by submitting the problem to th ## Practice problems - [Library Checker - Minimum Enclosing Circle](https://judge.yosupo.jp/problem/minimum_enclosing_circle) +- [BOI 2002 - Aliens](https://www.spoj.com/problems/ALIENS) \ No newline at end of file From 242fb917f39b0b1e7ee7e5b70f4fff495470a228 Mon Sep 17 00:00:00 2001 From: AYUSH KUMAR TIWARI <139953157+ayushkrtiwari@users.noreply.github.com> Date: Sun, 24 Aug 2025 22:36:02 +0530 Subject: [PATCH 74/86] GCPC 2017 Buildings, Burnside Lemma (#1504) --- src/combinatorics/burnside.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/combinatorics/burnside.md b/src/combinatorics/burnside.md index 5479c3703..6df2bd19f 100644 --- a/src/combinatorics/burnside.md +++ b/src/combinatorics/burnside.md @@ -280,3 +280,4 @@ int solve(int n, int m) { * [SPOJ - Sorting Machine](https://www.spoj.com/problems/SRTMACH/) * [Project Euler - Pizza Toppings](https://projecteuler.net/problem=281) * [ICPC 2011 SERCP - Alphabet Soup](https://basecamp.eolymp.com/tr/problems/3064) +* [GCPC 2017 - Buildings](https://basecamp.eolymp.com/en/problems/11615) From 74b370ccf42adba9b946563dfb1512b3b76b3110 Mon Sep 17 00:00:00 2001 From: Michael Hayter Date: Mon, 25 Aug 2025 02:45:10 -0400 Subject: [PATCH 75/86] relocated lis to dp section/add redirect + add relevant links to intro-to_dp (#1457) --- src/dynamic_programming/intro-to-dp.md | 6 +- .../longest_increasing_subsequence.md | 360 +++++++++++++++++ src/navigation.md | 2 +- .../longest_increasing_subsequence.md | 361 +----------------- 4 files changed, 366 insertions(+), 363 deletions(-) create mode 100644 src/dynamic_programming/longest_increasing_subsequence.md diff --git a/src/dynamic_programming/intro-to-dp.md b/src/dynamic_programming/intro-to-dp.md index 8bc33fd82..562a46c77 100644 --- a/src/dynamic_programming/intro-to-dp.md +++ b/src/dynamic_programming/intro-to-dp.md @@ -132,9 +132,9 @@ One of the tricks to getting better at dynamic programming is to study some of t ## Classic Dynamic Programming Problems | Name | Description/Example | | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 0-1 Knapsack | Given $W$, $N$, and $N$ items with weights $w_i$ and values $v_i$, what is the maximum $\sum_{i=1}^{k} v_i$ for each subset of items of size $k$ ($1 \le k \le N$) while ensuring $\sum_{i=1}^{k} w_i \le W$? | +| [0-1 Knapsack](../dynamic_programming/knapsack.md) | Given $W$, $N$, and $N$ items with weights $w_i$ and values $v_i$, what is the maximum $\sum_{i=1}^{k} v_i$ for each subset of items of size $k$ ($1 \le k \le N$) while ensuring $\sum_{i=1}^{k} w_i \le W$? | | Subset Sum | Given $N$ integers and $T$, determine whether there exists a subset of the given set whose elements sum up to the $T$. | -| Longest Increasing Subsequence (LIS) | You are given an array containing $N$ integers. Your task is to determine the LIS in the array, i.e., a subsequence where every element is larger than the previous one. | +| [Longest Increasing Subsequence (LIS)](../dynamic_programming/longest_increasing_subsequence.md) | You are given an array containing $N$ integers. Your task is to determine the LIS in the array, i.e., a subsequence where every element is larger than the previous one. | | Counting Paths in a 2D Array | Given $N$ and $M$, count all possible distinct paths from $(1,1)$ to $(N, M)$, where each step is either from $(i,j)$ to $(i+1,j)$ or $(i,j+1)$. | | Longest Common Subsequence | You are given strings $s$ and $t$. Find the length of the longest string that is a subsequence of both $s$ and $t$. | | Longest Path in a Directed Acyclic Graph (DAG) | Finding the longest path in Directed Acyclic Graph (DAG). | @@ -143,7 +143,7 @@ One of the tricks to getting better at dynamic programming is to study some of t | Edit Distance | The edit distance between two strings is the minimum number of operations required to transform one string into the other. Operations are ["Add", "Remove", "Replace"] | ## Related Topics -* Bitmask Dynamic Programming +* [Bitmask Dynamic Programming](../dynamic_programming/profile-dynamics.md) * Digit Dynamic Programming * Dynamic Programming on Trees diff --git a/src/dynamic_programming/longest_increasing_subsequence.md b/src/dynamic_programming/longest_increasing_subsequence.md new file mode 100644 index 000000000..a4c8f0fe4 --- /dev/null +++ b/src/dynamic_programming/longest_increasing_subsequence.md @@ -0,0 +1,360 @@ +--- +tags: + - Translated +e_maxx_link: longest_increasing_subseq_log +--- + +# Longest increasing subsequence + +We are given an array with $n$ numbers: $a[0 \dots n-1]$. +The task is to find the longest, strictly increasing, subsequence in $a$. + +Formally we look for the longest sequence of indices $i_1, \dots i_k$ such that + +$$i_1 < i_2 < \dots < i_k,\quad +a[i_1] < a[i_2] < \dots < a[i_k]$$ + +In this article we discuss multiple algorithms for solving this task. +Also we will discuss some other problems, that can be reduced to this problem. + +## Solution in $O(n^2)$ with dynamic programming {data-toc-label="Solution in O(n^2) with dynamic programming"} + +Dynamic programming is a very general technique that allows to solve a huge class of problems. +Here we apply the technique for our specific task. + +First we will search only for the **length** of the longest increasing subsequence, and only later learn how to restore the subsequence itself. + +### Finding the length + +To accomplish this task, we define an array $d[0 \dots n-1]$, where $d[i]$ is the length of the longest increasing subsequence that ends in the element at index $i$. + +!!! example + + $$\begin{array}{ll} + a &= \{8, 3, 4, 6, 5, 2, 0, 7, 9, 1\} \\ + d &= \{1, 1, 2, 3, 3, 1, 1, 4, 5, 2\} + \end{array}$$ + + The longest increasing subsequence that ends at index 4 is $\{3, 4, 5\}$ with a length of 3, the longest ending at index 8 is either $\{3, 4, 5, 7, 9\}$ or $\{3, 4, 6, 7, 9\}$, both having length 5, and the longest ending at index 9 is $\{0, 1\}$ having length 2. + +We will compute this array gradually: first $d[0]$, then $d[1]$, and so on. +After this array is computed, the answer to the problem will be the maximum value in the array $d[]$. + +So let the current index be $i$. +I.e. we want to compute the value $d[i]$ and all previous values $d[0], \dots, d[i-1]$ are already known. +Then there are two options: + +- $d[i] = 1$: the required subsequence consists only of the element $a[i]$. + +- $d[i] > 1$: The subsequence will end at $a[i]$, and right before it will be some number $a[j]$ with $j < i$ and $a[j] < a[i]$. + + It's easy to see, that the subsequence ending in $a[j]$ will itself be one of the longest increasing subsequences that ends in $a[j]$. + The number $a[i]$ just extends that longest increasing subsequence by one number. + + Therefore, we can just iterate over all $j < i$ with $a[j] < a[i]$, and take the longest sequence that we get by appending $a[i]$ to the longest increasing subsequence ending in $a[j]$. + The longest increasing subsequence ending in $a[j]$ has length $d[j]$, extending it by one gives the length $d[j] + 1$. + + $$d[i] = \max_{\substack{j < i \\\\ a[j] < a[i]}} \left(d[j] + 1\right)$$ + +If we combine these two cases we get the final answer for $d[i]$: + +$$d[i] = \max\left(1, \max_{\substack{j < i \\\\ a[j] < a[i]}} \left(d[j] + 1\right)\right)$$ + +### Implementation + +Here is an implementation of the algorithm described above, which computes the length of the longest increasing subsequence. + +```{.cpp file=lis_n2} +int lis(vector const& a) { + int n = a.size(); + vector d(n, 1); + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (a[j] < a[i]) + d[i] = max(d[i], d[j] + 1); + } + } + + int ans = d[0]; + for (int i = 1; i < n; i++) { + ans = max(ans, d[i]); + } + return ans; +} +``` + +### Restoring the subsequence + +So far we only learned how to find the length of the subsequence, but not how to find the subsequence itself. + +To be able to restore the subsequence we generate an additional auxiliary array $p[0 \dots n-1]$ that we will compute alongside the array $d[]$. +$p[i]$ will be the index $j$ of the second last element in the longest increasing subsequence ending in $i$. +In other words the index $p[i]$ is the same index $j$ at which the highest value $d[i]$ was obtained. +This auxiliary array $p[]$ points in some sense to the ancestors. + +Then to derive the subsequence, we just start at the index $i$ with the maximal $d[i]$, and follow the ancestors until we deduced the entire subsequence, i.e. until we reach the element with $d[i] = 1$. + +### Implementation of restoring + +We will change the code from the previous sections a little bit. +We will compute the array $p[]$ alongside $d[]$, and afterwards compute the subsequence. + +For convenience we originally assign the ancestors with $p[i] = -1$. +For elements with $d[i] = 1$, the ancestors value will remain $-1$, which will be slightly more convenient for restoring the subsequence. + +```{.cpp file=lis_n2_restore} +vector lis(vector const& a) { + int n = a.size(); + vector d(n, 1), p(n, -1); + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (a[j] < a[i] && d[i] < d[j] + 1) { + d[i] = d[j] + 1; + p[i] = j; + } + } + } + + int ans = d[0], pos = 0; + for (int i = 1; i < n; i++) { + if (d[i] > ans) { + ans = d[i]; + pos = i; + } + } + + vector subseq; + while (pos != -1) { + subseq.push_back(a[pos]); + pos = p[pos]; + } + reverse(subseq.begin(), subseq.end()); + return subseq; +} +``` + +### Alternative way of restoring the subsequence + +It is also possible to restore the subsequence without the auxiliary array $p[]$. +We can simply recalculate the current value of $d[i]$ and also see how the maximum was reached. + +This method leads to a slightly longer code, but in return we save some memory. + +## Solution in $O(n \log n)$ with dynamic programming and binary search {data-toc-label="Solution in O(n log n) with dynamic programming and binary search"} + +In order to obtain a faster solution for the problem, we construct a different dynamic programming solution that runs in $O(n^2)$, and then later improve it to $O(n \log n)$. + +We will use the dynamic programming array $d[0 \dots n]$. +This time $d[l]$ doesn't corresponds to the element $a[i]$ or to an prefix of the array. +$d[l]$ will be the smallest element at which an increasing subsequence of length $l$ ends. + +Initially we assume $d[0] = -\infty$ and for all other lengths $d[l] = \infty$. + +We will again gradually process the numbers, first $a[0]$, then $a[1]$, etc, and in each step maintain the array $d[]$ so that it is up to date. + +!!! example + + Given the array $a = \{8, 3, 4, 6, 5, 2, 0, 7, 9, 1\}$, here are all their prefixes and their dynamic programming array. + Notice, that the values of the array don't always change at the end. + + $$ + \begin{array}{ll} + \text{prefix} = \{\} &\quad d = \{-\infty, \infty, \dots\}\\ + \text{prefix} = \{8\} &\quad d = \{-\infty, 8, \infty, \dots\}\\ + \text{prefix} = \{8, 3\} &\quad d = \{-\infty, 3, \infty, \dots\}\\ + \text{prefix} = \{8, 3, 4\} &\quad d = \{-\infty, 3, 4, \infty, \dots\}\\ + \text{prefix} = \{8, 3, 4, 6\} &\quad d = \{-\infty, 3, 4, 6, \infty, \dots\}\\ + \text{prefix} = \{8, 3, 4, 6, 5\} &\quad d = \{-\infty, 3, 4, 5, \infty, \dots\}\\ + \text{prefix} = \{8, 3, 4, 6, 5, 2\} &\quad d = \{-\infty, 2, 4, 5, \infty, \dots \}\\ + \text{prefix} = \{8, 3, 4, 6, 5, 2, 0\} &\quad d = \{-\infty, 0, 4, 5, \infty, \dots \}\\ + \text{prefix} = \{8, 3, 4, 6, 5, 2, 0, 7\} &\quad d = \{-\infty, 0, 4, 5, 7, \infty, \dots \}\\ + \text{prefix} = \{8, 3, 4, 6, 5, 2, 0, 7, 9\} &\quad d = \{-\infty, 0, 4, 5, 7, 9, \infty, \dots \}\\ + \text{prefix} = \{8, 3, 4, 6, 5, 2, 0, 7, 9, 1\} &\quad d = \{-\infty, 0, 1, 5, 7, 9, \infty, \dots \}\\ + \end{array} + $$ + +When we process $a[i]$, we can ask ourselves. +What have the conditions to be, that we write the current number $a[i]$ into the $d[0 \dots n]$ array? + +We set $d[l] = a[i]$, if there is a longest increasing sequence of length $l$ that ends in $a[i]$, and there is no longest increasing sequence of length $l$ that ends in a smaller number. +Similar to the previous approach, if we remove the number $a[i]$ from the longest increasing sequence of length $l$, we get another longest increasing sequence of length $l -1$. +So we want to extend a longest increasing sequence of length $l - 1$ by the number $a[i]$, and obviously the longest increasing sequence of length $l - 1$ that ends with the smallest element will work the best, in other words the sequence of length $l-1$ that ends in element $d[l-1]$. + +There is a longest increasing sequence of length $l - 1$ that we can extend with the number $a[i]$, exactly if $d[l-1] < a[i]$. +So we can just iterate over each length $l$, and check if we can extend a longest increasing sequence of length $l - 1$ by checking the criteria. + +Additionally we also need to check, if we maybe have already found a longest increasing sequence of length $l$ with a smaller number at the end. +So we only update if $a[i] < d[l]$. + +After processing all the elements of $a[]$ the length of the desired subsequence is the largest $l$ with $d[l] < \infty$. + +```{.cpp file=lis_method2_n2} +int lis(vector const& a) { + int n = a.size(); + const int INF = 1e9; + vector d(n+1, INF); + d[0] = -INF; + + for (int i = 0; i < n; i++) { + for (int l = 1; l <= n; l++) { + if (d[l-1] < a[i] && a[i] < d[l]) + d[l] = a[i]; + } + } + + int ans = 0; + for (int l = 0; l <= n; l++) { + if (d[l] < INF) + ans = l; + } + return ans; +} +``` + +We now make two important observations. + +1. The array $d$ will always be sorted: + $d[l-1] < d[l]$ for all $i = 1 \dots n$. + + This is trivial, as you can just remove the last element from the increasing subsequence of length $l$, and you get a increasing subsequence of length $l-1$ with a smaller ending number. + +2. The element $a[i]$ will only update at most one value $d[l]$. + + This follows immediately from the above implementation. + There can only be one place in the array with $d[l-1] < a[i] < d[l]$. + +Thus we can find this element in the array $d[]$ using [binary search](../num_methods/binary_search.md) in $O(\log n)$. +In fact we can simply look in the array $d[]$ for the first number that is strictly greater than $a[i]$, and we try to update this element in the same way as the above implementation. + +### Implementation + +This gives us the improved $O(n \log n)$ implementation: + +```{.cpp file=lis_method2_nlogn} +int lis(vector const& a) { + int n = a.size(); + const int INF = 1e9; + vector d(n+1, INF); + d[0] = -INF; + + for (int i = 0; i < n; i++) { + int l = upper_bound(d.begin(), d.end(), a[i]) - d.begin(); + if (d[l-1] < a[i] && a[i] < d[l]) + d[l] = a[i]; + } + + int ans = 0; + for (int l = 0; l <= n; l++) { + if (d[l] < INF) + ans = l; + } + return ans; +} +``` + +### Restoring the subsequence + +It is also possible to restore the subsequence using this approach. +This time we have to maintain two auxiliary arrays. +One that tells us the index of the elements in $d[]$. +And again we have to create an array of "ancestors" $p[i]$. +$p[i]$ will be the index of the previous element for the optimal subsequence ending in element $i$. + +It's easy to maintain these two arrays in the course of iteration over the array $a[]$ alongside the computations of $d[]$. +And at the end it is not difficult to restore the desired subsequence using these arrays. + +## Solution in $O(n \log n)$ with data structures {data-toc-label="Solution in O(n log n) with data structures"} + +Instead of the above method for computing the longest increasing subsequence in $O(n \log n)$ we can also solve the problem in a different way: using some simple data structures. + +Let's go back to the first method. +Remember that $d[i]$ is the value $d[j] + 1$ with $j < i$ and $a[j] < a[i]$. + +Thus if we define an additional array $t[]$ such that + +$$t[a[i]] = d[i],$$ + +then the problem of computing the value $d[i]$ is equivalent to finding the **maximum value in a prefix** of the array $t[]$: + +$$d[i] = \max\left(t[0 \dots a[i] - 1] + 1\right)$$ + +The problem of finding the maximum of a prefix of an array (which changes) is a standard problem that can be solved by many different data structures. +For instance we can use a [Segment tree](../data_structures/segment_tree.md) or a [Fenwick tree](../data_structures/fenwick.md). + +This method has obviously some **shortcomings**: +in terms of length and complexity of the implementation this approach will be worse than the method using binary search. +In addition if the input numbers $a[i]$ are especially large, then we would have to use some tricks, like compressing the numbers (i.e. renumber them from $0$ to $n-1$), or use a dynamic segment tree (only generate the branches of the tree that are important). +Otherwise the memory consumption will be too high. + +On the other hand this method has also some **advantages**: +with this method you don't have to think about any tricky properties in the dynamic programming solution. +And this approach allows us to generalize the problem very easily (see below). + +## Related tasks + +Here are several problems that are closely related to the problem of finding the longest increasing subsequence. + +### Longest non-decreasing subsequence + +This is in fact nearly the same problem. +Only now it is allowed to use identical numbers in the subsequence. + +The solution is essentially also nearly the same. +We just have to change the inequality signs, and make a slight modification to the binary search. + +### Number of longest increasing subsequences + +We can use the first discussed method, either the $O(n^2)$ version or the version using data structures. +We only have to additionally store in how many ways we can obtain longest increasing subsequences ending in the values $d[i]$. + +The number of ways to form a longest increasing subsequences ending in $a[i]$ is the sum of all ways for all longest increasing subsequences ending in $j$ where $d[j]$ is maximal. +There can be multiple such $j$, so we need to sum all of them. + +Using a Segment tree this approach can also be implemented in $O(n \log n)$. + +It is not possible to use the binary search approach for this task. + +### Smallest number of non-increasing subsequences covering a sequence + +For a given array with $n$ numbers $a[0 \dots n - 1]$ we have to colorize the numbers in the smallest number of colors, so that each color forms a non-increasing subsequence. + +To solve this, we notice that the minimum number of required colors is equal to the length of the longest increasing subsequence. + +**Proof**: +We need to prove the **duality** of these two problems. + +Let's denote by $x$ the length of the longest increasing subsequence and by $y$ the least number of non-increasing subsequences that form a cover. +We need to prove that $x = y$. + +It is clear that $y < x$ is not possible, because if we have $x$ strictly increasing elements, than no two can be part of the same non-increasing subsequence. +Therefore we have $y \ge x$. + +We now show that $y > x$ is not possible by contradiction. +Suppose that $y > x$. +Then we consider any optimal set of $y$ non-increasing subsequences. +We transform this in set in the following way: +as long as there are two such subsequences such that the first begins before the second subsequence, and the first sequence start with a number greater than or equal to the second, then we unhook this starting number and attach it to the beginning of second. +After a finite number of steps we have $y$ subsequences, and their starting numbers will form an increasing subsequence of length $y$. +Since we assumed that $y > x$ we reached a contradiction. + +Thus it follows that $y = x$. + +**Restoring the sequences**: +The desired partition of the sequence into subsequences can be done greedily. +I.e. go from left to right and assign the current number or that subsequence ending with the minimal number which is greater than or equal to the current one. + +## Practice Problems + +- [ACMSGURU - "North-East"](http://codeforces.com/problemsets/acmsguru/problem/99999/521) +- [Codeforces - LCIS](http://codeforces.com/problemset/problem/10/D) +- [Codeforces - Tourist](http://codeforces.com/contest/76/problem/F) +- [SPOJ - DOSA](https://www.spoj.com/problems/DOSA/) +- [SPOJ - HMLIS](https://www.spoj.com/problems/HMLIS/) +- [SPOJ - ONEXLIS](https://www.spoj.com/problems/ONEXLIS/) +- [SPOJ - SUPPER](http://www.spoj.com/problems/SUPPER/) +- [Topcoder - AutoMarket](https://community.topcoder.com/stat?c=problem_statement&pm=3937&rd=6532) +- [Topcoder - BridgeArrangement](https://community.topcoder.com/stat?c=problem_statement&pm=2967&rd=5881) +- [Topcoder - IntegerSequence](https://community.topcoder.com/stat?c=problem_statement&pm=5922&rd=8075) +- [UVA - Back To Edit Distance](https://onlinejudge.org/external/127/12747.pdf) +- [UVA - Happy Birthday](https://onlinejudge.org/external/120/12002.pdf) +- [UVA - Tiling Up Blocks](https://onlinejudge.org/external/11/1196.pdf) diff --git a/src/navigation.md b/src/navigation.md index b0ca42e24..c89a21a06 100644 --- a/src/navigation.md +++ b/src/navigation.md @@ -63,6 +63,7 @@ search: - Dynamic Programming - [Introduction to Dynamic Programming](dynamic_programming/intro-to-dp.md) - [Knapsack Problem](dynamic_programming/knapsack.md) + - [Longest increasing subsequence](dynamic_programming/longest_increasing_subsequence.md) - DP optimizations - [Divide and Conquer DP](dynamic_programming/divide-and-conquer-dp.md) - [Knuth's Optimization](dynamic_programming/knuth-optimization.md) @@ -205,7 +206,6 @@ search: - Miscellaneous - Sequences - [RMQ task (Range Minimum Query - the smallest element in an interval)](sequences/rmq.md) - - [Longest increasing subsequence](sequences/longest_increasing_subsequence.md) - [Search the subsegment with the maximum/minimum sum](others/maximum_average_segment.md) - [K-th order statistic in O(N)](sequences/k-th.md) - [MEX task (Minimal Excluded element in an array)](sequences/mex.md) diff --git a/src/sequences/longest_increasing_subsequence.md b/src/sequences/longest_increasing_subsequence.md index dca4f020b..5e8e9df53 100644 --- a/src/sequences/longest_increasing_subsequence.md +++ b/src/sequences/longest_increasing_subsequence.md @@ -1,360 +1,3 @@ ---- -tags: - - Translated -e_maxx_link: longest_increasing_subseq_log ---- - + # Longest increasing subsequence - -We are given an array with $n$ numbers: $a[0 \dots n-1]$. -The task is to find the longest, strictly increasing, subsequence in $a$. - -Formally we look for the longest sequence of indices $i_1, \dots i_k$ such that - -$$i_1 < i_2 < \dots < i_k,\quad -a[i_1] < a[i_2] < \dots < a[i_k]$$ - -In this article we discuss multiple algorithms for solving this task. -Also we will discuss some other problems, that can be reduced to this problem. - -## Solution in $O(n^2)$ with dynamic programming {data-toc-label="Solution in O(n^2) with dynamic programming"} - -Dynamic programming is a very general technique that allows to solve a huge class of problems. -Here we apply the technique for our specific task. - -First we will search only for the **length** of the longest increasing subsequence, and only later learn how to restore the subsequence itself. - -### Finding the length - -To accomplish this task, we define an array $d[0 \dots n-1]$, where $d[i]$ is the length of the longest increasing subsequence that ends in the element at index $i$. - -!!! example - - $$\begin{array}{ll} - a &= \{8, 3, 4, 6, 5, 2, 0, 7, 9, 1\} \\ - d &= \{1, 1, 2, 3, 3, 1, 1, 4, 5, 2\} - \end{array}$$ - - The longest increasing subsequence that ends at index 4 is $\{3, 4, 5\}$ with a length of 3, the longest ending at index 8 is either $\{3, 4, 5, 7, 9\}$ or $\{3, 4, 6, 7, 9\}$, both having length 5, and the longest ending at index 9 is $\{0, 1\}$ having length 2. - -We will compute this array gradually: first $d[0]$, then $d[1]$, and so on. -After this array is computed, the answer to the problem will be the maximum value in the array $d[]$. - -So let the current index be $i$. -I.e. we want to compute the value $d[i]$ and all previous values $d[0], \dots, d[i-1]$ are already known. -Then there are two options: - -- $d[i] = 1$: the required subsequence consists only of the element $a[i]$. - -- $d[i] > 1$: The subsequence will end at $a[i]$, and right before it will be some number $a[j]$ with $j < i$ and $a[j] < a[i]$. - - It's easy to see, that the subsequence ending in $a[j]$ will itself be one of the longest increasing subsequences that ends in $a[j]$. - The number $a[i]$ just extends that longest increasing subsequence by one number. - - Therefore, we can just iterate over all $j < i$ with $a[j] < a[i]$, and take the longest sequence that we get by appending $a[i]$ to the longest increasing subsequence ending in $a[j]$. - The longest increasing subsequence ending in $a[j]$ has length $d[j]$, extending it by one gives the length $d[j] + 1$. - - $$d[i] = \max_{\substack{j < i \\\\ a[j] < a[i]}} \left(d[j] + 1\right)$$ - -If we combine these two cases we get the final answer for $d[i]$: - -$$d[i] = \max\left(1, \max_{\substack{j < i \\\\ a[j] < a[i]}} \left(d[j] + 1\right)\right)$$ - -### Implementation - -Here is an implementation of the algorithm described above, which computes the length of the longest increasing subsequence. - -```{.cpp file=lis_n2} -int lis(vector const& a) { - int n = a.size(); - vector d(n, 1); - for (int i = 0; i < n; i++) { - for (int j = 0; j < i; j++) { - if (a[j] < a[i]) - d[i] = max(d[i], d[j] + 1); - } - } - - int ans = d[0]; - for (int i = 1; i < n; i++) { - ans = max(ans, d[i]); - } - return ans; -} -``` - -### Restoring the subsequence - -So far we only learned how to find the length of the subsequence, but not how to find the subsequence itself. - -To be able to restore the subsequence we generate an additional auxiliary array $p[0 \dots n-1]$ that we will compute alongside the array $d[]$. -$p[i]$ will be the index $j$ of the second last element in the longest increasing subsequence ending in $i$. -In other words the index $p[i]$ is the same index $j$ at which the highest value $d[i]$ was obtained. -This auxiliary array $p[]$ points in some sense to the ancestors. - -Then to derive the subsequence, we just start at the index $i$ with the maximal $d[i]$, and follow the ancestors until we deduced the entire subsequence, i.e. until we reach the element with $d[i] = 1$. - -### Implementation of restoring - -We will change the code from the previous sections a little bit. -We will compute the array $p[]$ alongside $d[]$, and afterwards compute the subsequence. - -For convenience we originally assign the ancestors with $p[i] = -1$. -For elements with $d[i] = 1$, the ancestors value will remain $-1$, which will be slightly more convenient for restoring the subsequence. - -```{.cpp file=lis_n2_restore} -vector lis(vector const& a) { - int n = a.size(); - vector d(n, 1), p(n, -1); - for (int i = 0; i < n; i++) { - for (int j = 0; j < i; j++) { - if (a[j] < a[i] && d[i] < d[j] + 1) { - d[i] = d[j] + 1; - p[i] = j; - } - } - } - - int ans = d[0], pos = 0; - for (int i = 1; i < n; i++) { - if (d[i] > ans) { - ans = d[i]; - pos = i; - } - } - - vector subseq; - while (pos != -1) { - subseq.push_back(a[pos]); - pos = p[pos]; - } - reverse(subseq.begin(), subseq.end()); - return subseq; -} -``` - -### Alternative way of restoring the subsequence - -It is also possible to restore the subsequence without the auxiliary array $p[]$. -We can simply recalculate the current value of $d[i]$ and also see how the maximum was reached. - -This method leads to a slightly longer code, but in return we save some memory. - -## Solution in $O(n \log n)$ with dynamic programming and binary search {data-toc-label="Solution in O(n log n) with dynamic programming and binary search"} - -In order to obtain a faster solution for the problem, we construct a different dynamic programming solution that runs in $O(n^2)$, and then later improve it to $O(n \log n)$. - -We will use the dynamic programming array $d[0 \dots n]$. -This time $d[l]$ doesn't corresponds to the element $a[i]$ or to an prefix of the array. -$d[l]$ will be the smallest element at which an increasing subsequence of length $l$ ends. - -Initially we assume $d[0] = -\infty$ and for all other lengths $d[l] = \infty$. - -We will again gradually process the numbers, first $a[0]$, then $a[1]$, etc, and in each step maintain the array $d[]$ so that it is up to date. - -!!! example - - Given the array $a = \{8, 3, 4, 6, 5, 2, 0, 7, 9, 1\}$, here are all their prefixes and their dynamic programming array. - Notice, that the values of the array don't always change at the end. - - $$ - \begin{array}{ll} - \text{prefix} = \{\} &\quad d = \{-\infty, \infty, \dots\}\\ - \text{prefix} = \{8\} &\quad d = \{-\infty, 8, \infty, \dots\}\\ - \text{prefix} = \{8, 3\} &\quad d = \{-\infty, 3, \infty, \dots\}\\ - \text{prefix} = \{8, 3, 4\} &\quad d = \{-\infty, 3, 4, \infty, \dots\}\\ - \text{prefix} = \{8, 3, 4, 6\} &\quad d = \{-\infty, 3, 4, 6, \infty, \dots\}\\ - \text{prefix} = \{8, 3, 4, 6, 5\} &\quad d = \{-\infty, 3, 4, 5, \infty, \dots\}\\ - \text{prefix} = \{8, 3, 4, 6, 5, 2\} &\quad d = \{-\infty, 2, 4, 5, \infty, \dots \}\\ - \text{prefix} = \{8, 3, 4, 6, 5, 2, 0\} &\quad d = \{-\infty, 0, 4, 5, \infty, \dots \}\\ - \text{prefix} = \{8, 3, 4, 6, 5, 2, 0, 7\} &\quad d = \{-\infty, 0, 4, 5, 7, \infty, \dots \}\\ - \text{prefix} = \{8, 3, 4, 6, 5, 2, 0, 7, 9\} &\quad d = \{-\infty, 0, 4, 5, 7, 9, \infty, \dots \}\\ - \text{prefix} = \{8, 3, 4, 6, 5, 2, 0, 7, 9, 1\} &\quad d = \{-\infty, 0, 1, 5, 7, 9, \infty, \dots \}\\ - \end{array} - $$ - -When we process $a[i]$, we can ask ourselves. -Under what conditions should we write the current number $a[i]$ into the $d[0 \dots n]$ array? - -We set $d[l] = a[i]$, if there is a longest increasing sequence of length $l$ that ends in $a[i]$, and there is no longest increasing sequence of length $l$ that ends in a smaller number. -Similar to the previous approach, if we remove the number $a[i]$ from the longest increasing sequence of length $l$, we get another longest increasing sequence of length $l -1$. -So we want to extend a longest increasing sequence of length $l - 1$ by the number $a[i]$, and obviously the longest increasing sequence of length $l - 1$ that ends with the smallest element will work the best, in other words the sequence of length $l-1$ that ends in element $d[l-1]$. - -There is a longest increasing sequence of length $l - 1$ that we can extend with the number $a[i]$, exactly if $d[l-1] < a[i]$. -So we can just iterate over each length $l$, and check if we can extend a longest increasing sequence of length $l - 1$ by checking the criteria. - -Additionally we also need to check, if we maybe have already found a longest increasing sequence of length $l$ with a smaller number at the end. -So we only update if $a[i] < d[l]$. - -After processing all the elements of $a[]$ the length of the desired subsequence is the largest $l$ with $d[l] < \infty$. - -```{.cpp file=lis_method2_n2} -int lis(vector const& a) { - int n = a.size(); - const int INF = 1e9; - vector d(n+1, INF); - d[0] = -INF; - - for (int i = 0; i < n; i++) { - for (int l = 1; l <= n; l++) { - if (d[l-1] < a[i] && a[i] < d[l]) - d[l] = a[i]; - } - } - - int ans = 0; - for (int l = 0; l <= n; l++) { - if (d[l] < INF) - ans = l; - } - return ans; -} -``` - -We now make two important observations. - -1. The array $d$ will always be sorted: - $d[l-1] < d[l]$ for all $i = 1 \dots n$. - - This is trivial, as you can just remove the last element from the increasing subsequence of length $l$, and you get a increasing subsequence of length $l-1$ with a smaller ending number. - -2. The element $a[i]$ will only update at most one value $d[l]$. - - This follows immediately from the above implementation. - There can only be one place in the array with $d[l-1] < a[i] < d[l]$. - -Thus we can find this element in the array $d[]$ using [binary search](../num_methods/binary_search.md) in $O(\log n)$. -In fact we can simply look in the array $d[]$ for the first number that is strictly greater than $a[i]$, and we try to update this element in the same way as the above implementation. - -### Implementation - -This gives us the improved $O(n \log n)$ implementation: - -```{.cpp file=lis_method2_nlogn} -int lis(vector const& a) { - int n = a.size(); - const int INF = 1e9; - vector d(n+1, INF); - d[0] = -INF; - - for (int i = 0; i < n; i++) { - int l = upper_bound(d.begin(), d.end(), a[i]) - d.begin(); - if (d[l-1] < a[i] && a[i] < d[l]) - d[l] = a[i]; - } - - int ans = 0; - for (int l = 0; l <= n; l++) { - if (d[l] < INF) - ans = l; - } - return ans; -} -``` - -### Restoring the subsequence - -It is also possible to restore the subsequence using this approach. -This time we have to maintain two auxiliary arrays. -One that tells us the index of the elements in $d[]$. -And again we have to create an array of "ancestors" $p[i]$. -$p[i]$ will be the index of the previous element for the optimal subsequence ending in element $i$. - -It's easy to maintain these two arrays in the course of iteration over the array $a[]$ alongside the computations of $d[]$. -And at the end it is not difficult to restore the desired subsequence using these arrays. - -## Solution in $O(n \log n)$ with data structures {data-toc-label="Solution in O(n log n) with data structures"} - -Instead of the above method for computing the longest increasing subsequence in $O(n \log n)$ we can also solve the problem in a different way: using some simple data structures. - -Let's go back to the first method. -Remember that $d[i]$ is the value $d[j] + 1$ with $j < i$ and $a[j] < a[i]$. - -Thus if we define an additional array $t[]$ such that - -$$t[a[i]] = d[i],$$ - -then the problem of computing the value $d[i]$ is equivalent to finding the **maximum value in a prefix** of the array $t[]$: - -$$d[i] = \max\left(t[0 \dots a[i] - 1] + 1\right)$$ - -The problem of finding the maximum of a prefix of an array (which changes) is a standard problem that can be solved by many different data structures. -For instance we can use a [Segment tree](../data_structures/segment_tree.md) or a [Fenwick tree](../data_structures/fenwick.md). - -This method has obviously some **shortcomings**: -in terms of length and complexity of the implementation this approach will be worse than the method using binary search. -In addition if the input numbers $a[i]$ are especially large, then we would have to use some tricks, like compressing the numbers (i.e. renumber them from $0$ to $n-1$), or use a dynamic segment tree (only generate the branches of the tree that are important). -Otherwise the memory consumption will be too high. - -On the other hand this method has also some **advantages**: -with this method you don't have to think about any tricky properties in the dynamic programming solution. -And this approach allows us to generalize the problem very easily (see below). - -## Related tasks - -Here are several problems that are closely related to the problem of finding the longest increasing subsequence. - -### Longest non-decreasing subsequence - -This is in fact nearly the same problem. -Only now it is allowed to use identical numbers in the subsequence. - -The solution is essentially also nearly the same. -We just have to change the inequality signs, and make a slight modification to the binary search. - -### Number of longest increasing subsequences - -We can use the first discussed method, either the $O(n^2)$ version or the version using data structures. -We only have to additionally store in how many ways we can obtain longest increasing subsequences ending in the values $d[i]$. - -The number of ways to form a longest increasing subsequences ending in $a[i]$ is the sum of all ways for all longest increasing subsequences ending in $j$ where $d[j]$ is maximal. -There can be multiple such $j$, so we need to sum all of them. - -Using a Segment tree this approach can also be implemented in $O(n \log n)$. - -It is not possible to use the binary search approach for this task. - -### Smallest number of non-increasing subsequences covering a sequence - -For a given array with $n$ numbers $a[0 \dots n - 1]$ we have to colorize the numbers in the smallest number of colors, so that each color forms a non-increasing subsequence. - -To solve this, we notice that the minimum number of required colors is equal to the length of the longest increasing subsequence. - -**Proof**: -We need to prove the **duality** of these two problems. - -Let's denote by $x$ the length of the longest increasing subsequence and by $y$ the least number of non-increasing subsequences that form a cover. -We need to prove that $x = y$. - -It is clear that $y < x$ is not possible, because if we have $x$ strictly increasing elements, than no two can be part of the same non-increasing subsequence. -Therefore we have $y \ge x$. - -We now show that $y > x$ is not possible by contradiction. -Suppose that $y > x$. -Then we consider any optimal set of $y$ non-increasing subsequences. -We transform this in set in the following way: -as long as there are two such subsequences such that the first begins before the second subsequence, and the first sequence start with a number greater than or equal to the second, then we unhook this starting number and attach it to the beginning of second. -After a finite number of steps we have $y$ subsequences, and their starting numbers will form an increasing subsequence of length $y$. -Since we assumed that $y > x$ we reached a contradiction. - -Thus it follows that $y = x$. - -**Restoring the sequences**: -The desired partition of the sequence into subsequences can be done greedily. -I.e. go from left to right and assign the current number or that subsequence ending with the minimal number which is greater than or equal to the current one. - -## Practice Problems - -- [ACMSGURU - "North-East"](http://codeforces.com/problemsets/acmsguru/problem/99999/521) -- [Codeforces - LCIS](http://codeforces.com/problemset/problem/10/D) -- [Codeforces - Tourist](http://codeforces.com/contest/76/problem/F) -- [SPOJ - DOSA](https://www.spoj.com/problems/DOSA/) -- [SPOJ - HMLIS](https://www.spoj.com/problems/HMLIS/) -- [SPOJ - ONEXLIS](https://www.spoj.com/problems/ONEXLIS/) -- [SPOJ - SUPPER](http://www.spoj.com/problems/SUPPER/) -- [Topcoder - AutoMarket](https://community.topcoder.com/stat?c=problem_statement&pm=3937&rd=6532) -- [Topcoder - BridgeArrangement](https://community.topcoder.com/stat?c=problem_statement&pm=2967&rd=5881) -- [Topcoder - IntegerSequence](https://community.topcoder.com/stat?c=problem_statement&pm=5922&rd=8075) -- [UVA - Back To Edit Distance](https://onlinejudge.org/external/127/12747.pdf) -- [UVA - Happy Birthday](https://onlinejudge.org/external/120/12002.pdf) -- [UVA - Tiling Up Blocks](https://onlinejudge.org/external/11/1196.pdf) +This article has been moved to a [Longest increasing subsequence](../dynamic_programming/longest_increasing_subsequence.md). \ No newline at end of file From 647caba14bab6133bfc2cc9895c647fab8ed99f3 Mon Sep 17 00:00:00 2001 From: AYUSH KUMAR TIWARI <139953157+ayushkrtiwari@users.noreply.github.com> Date: Mon, 25 Aug 2025 19:02:51 +0530 Subject: [PATCH 76/86] Neated Up Problem Links (#1506) --- src/geometry/point-in-convex-polygon.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geometry/point-in-convex-polygon.md b/src/geometry/point-in-convex-polygon.md index 7d6e630b7..edc84ed61 100644 --- a/src/geometry/point-in-convex-polygon.md +++ b/src/geometry/point-in-convex-polygon.md @@ -120,5 +120,5 @@ bool pointInConvexPolygon(pt point) { ``` ## Problems -[SGU253 Theodore Roosevelt](https://codeforces.com/problemsets/acmsguru/problem/99999/253) -[Codeforces 55E Very simple problem](https://codeforces.com/contest/55/problem/E) +* [SGU253 Theodore Roosevelt](https://codeforces.com/problemsets/acmsguru/problem/99999/253) +* [Codeforces 55E Very simple problem](https://codeforces.com/contest/55/problem/E) \ No newline at end of file From 6f7cf7a3c9a3a38052f60b3cf5437f279797733f Mon Sep 17 00:00:00 2001 From: AYUSH KUMAR TIWARI <139953157+ayushkrtiwari@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:46:53 +0530 Subject: [PATCH 77/86] CF 166B Polygons (#1509) --- src/geometry/point-in-convex-polygon.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/geometry/point-in-convex-polygon.md b/src/geometry/point-in-convex-polygon.md index edc84ed61..4b3b4a898 100644 --- a/src/geometry/point-in-convex-polygon.md +++ b/src/geometry/point-in-convex-polygon.md @@ -121,4 +121,5 @@ bool pointInConvexPolygon(pt point) { ## Problems * [SGU253 Theodore Roosevelt](https://codeforces.com/problemsets/acmsguru/problem/99999/253) -* [Codeforces 55E Very simple problem](https://codeforces.com/contest/55/problem/E) \ No newline at end of file +* [Codeforces 55E Very simple problem](https://codeforces.com/contest/55/problem/E) +* [Codeforces 166B Polygons](https://codeforces.com/problemset/problem/166/B) From fbdd91baaf8a263f035f942ebe2c183b3a5c9434 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Tomar <84472068+nikhil-kumar-tomar@users.noreply.github.com> Date: Mon, 25 Aug 2025 23:00:05 +0530 Subject: [PATCH 78/86] Fix typo in "Finding Bridges" Closes #1508 --- src/graph/bridge-searching.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/bridge-searching.md b/src/graph/bridge-searching.md index 48a52c1f6..c2d8f0ce6 100644 --- a/src/graph/bridge-searching.md +++ b/src/graph/bridge-searching.md @@ -22,7 +22,7 @@ Pick an arbitrary vertex of the graph $root$ and run [depth first search](depth- Now we have to learn to check this fact for each vertex efficiently. We'll use "time of entry into node" computed by the depth first search. -So, let $\mathtt{tin}[v]$ denote entry time for node $v$. We introduce an array $\mathtt{low}$ which will let us store the node with earliest entry time found in the DFS search that a node $v$ can reach with a single edge from itself or its descendants. $\mathtt{low}[v]$ is the minimum of $\mathtt{tin}[v]$, the entry times $\mathtt{tin}[p]$ for each node $p$ that is connected to node $v$ via a back-edge $(v, p)$ and the values of $\mathtt{low}[to]$ for each vertex $to$ which is a direct descendant of $v$ in the DFS tree: +So, let $\mathtt{tin}[v]$ denote entry time for node $v$. We introduce an array $\mathtt{low}$ which will let us store the earliest entry time of the node found in the DFS search that a node $v$ can reach with a single edge from itself or its descendants. $\mathtt{low}[v]$ is the minimum of $\mathtt{tin}[v]$, the entry times $\mathtt{tin}[p]$ for each node $p$ that is connected to node $v$ via a back-edge $(v, p)$ and the values of $\mathtt{low}[to]$ for each vertex $to$ which is a direct descendant of $v$ in the DFS tree: $$\mathtt{low}[v] = \min \left\{ \begin{array}{l} From f1570ffac3c8a1a4c2861a13a6eeff60eac4b3dc Mon Sep 17 00:00:00 2001 From: Nafis <34790351+Nafyaz@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:21:57 +0600 Subject: [PATCH 79/86] Add CSES problem in z-function.md (#1500) --- src/string/z-function.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/string/z-function.md b/src/string/z-function.md index c83938cb4..18be20931 100644 --- a/src/string/z-function.md +++ b/src/string/z-function.md @@ -204,6 +204,7 @@ The proof for this fact is the same as the solution which uses the [prefix funct ## Practice Problems +* [CSES - Finding Borders](https://cses.fi/problemset/task/1732) * [eolymp - Blocks of string](https://www.eolymp.com/en/problems/1309) * [Codeforces - Password [Difficulty: Easy]](http://codeforces.com/problemset/problem/126/B) * [UVA # 455 "Periodic Strings" [Difficulty: Medium]](http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=396) From e726bac69a878a624b63b164aec578f64d069a01 Mon Sep 17 00:00:00 2001 From: Zombiesalad1337 Date: Wed, 27 Aug 2025 11:13:56 +0530 Subject: [PATCH 80/86] Fix incorrect reference direction in DFS article --- src/graph/depth-first-search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/depth-first-search.md b/src/graph/depth-first-search.md index f65d27dd4..8ca547a69 100644 --- a/src/graph/depth-first-search.md +++ b/src/graph/depth-first-search.md @@ -44,7 +44,7 @@ For more details check out the implementation. The required topological ordering will be the vertices sorted in descending order of exit time. - * Check whether a given graph is acyclic and find cycles in a graph. (As mentioned above by counting back edges in every connected components). + * Check whether a given graph is acyclic and find cycles in a graph. (As mentioned below by counting back edges in every connected components). * Find strongly connected components in a directed graph: From d4d57e932395f995aef6c03c52da8b1754ff17d6 Mon Sep 17 00:00:00 2001 From: Akram Rakhmetulla <77340228+spike1236@users.noreply.github.com> Date: Sun, 31 Aug 2025 12:52:12 +0500 Subject: [PATCH 81/86] fix contribution pct display (#1514) --- src/overrides/partials/content.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/overrides/partials/content.html b/src/overrides/partials/content.html index babde6339..b70756be2 100644 --- a/src/overrides/partials/content.html +++ b/src/overrides/partials/content.html @@ -88,7 +88,7 @@

{{ page.title | d(config.site_name, true)}}

Contributors: From 5b0f90adf2b117c36fadf1de300f3d175110681f Mon Sep 17 00:00:00 2001 From: Aleksandr Mishukhin <100044766+aleksmish@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:45:21 +0300 Subject: [PATCH 82/86] fix typo Changed from "a segment intersect" to "a segment intersects" --- src/geometry/intersecting_segments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/intersecting_segments.md b/src/geometry/intersecting_segments.md index ac26c8fd5..ce61cd887 100644 --- a/src/geometry/intersecting_segments.md +++ b/src/geometry/intersecting_segments.md @@ -14,7 +14,7 @@ The naive solution algorithm is to iterate over all pairs of segments in $O(n^2) ## Algorithm Let's draw a vertical line $x = -\infty$ mentally and start moving this line to the right. -In the course of its movement, this line will meet with segments, and at each time a segment intersect with our line it intersects in exactly one point (we will assume that there are no vertical segments). +In the course of its movement, this line will meet with segments, and at each time a segment intersects with our line it intersects in exactly one point (we will assume that there are no vertical segments).
sweep line and line segment intersection From 282d3514472c0f61a609091f292e27e56924d9ba Mon Sep 17 00:00:00 2001 From: Aleksandr Mishukhin <100044766+aleksmish@users.noreply.github.com> Date: Wed, 10 Sep 2025 09:18:21 +0300 Subject: [PATCH 83/86] fix typo Changed from "to just looking" to "to just look" --- src/graph/finding-negative-cycle-in-graph.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/finding-negative-cycle-in-graph.md b/src/graph/finding-negative-cycle-in-graph.md index a9b87c7f9..e29927fcc 100644 --- a/src/graph/finding-negative-cycle-in-graph.md +++ b/src/graph/finding-negative-cycle-in-graph.md @@ -19,7 +19,7 @@ Bellman-Ford algorithm allows you to check whether there exists a cycle of negat The details of the algorithm are described in the article on the [Bellman-Ford](bellman_ford.md) algorithm. Here we'll describe only its application to this problem. -The standard implementation of Bellman-Ford looks for a negative cycle reachable from some starting vertex $v$ ; however, the algorithm can be modified to just looking for any negative cycle in the graph. +The standard implementation of Bellman-Ford looks for a negative cycle reachable from some starting vertex $v$ ; however, the algorithm can be modified to just look for any negative cycle in the graph. For this we need to put all the distance  $d[i]$  to zero and not infinity — as if we are looking for the shortest path from all vertices simultaneously; the validity of the detection of a negative cycle is not affected. Do $N$ iterations of Bellman-Ford algorithm. If there were no changes on the last iteration, there is no cycle of negative weight in the graph. Otherwise take a vertex the distance to which has changed, and go from it via its ancestors until a cycle is found. This cycle will be the desired cycle of negative weight. From 2f2966209cab35f58bd1085f8ff398eb2970bbc3 Mon Sep 17 00:00:00 2001 From: Aleksandr Mishukhin <100044766+aleksmish@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:29:18 +0300 Subject: [PATCH 84/86] fix typo Changed from "to just looking for" to "to just look for" --- src/graph/bellman_ford.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/bellman_ford.md b/src/graph/bellman_ford.md index d4ffdf655..b9f9ab626 100644 --- a/src/graph/bellman_ford.md +++ b/src/graph/bellman_ford.md @@ -201,7 +201,7 @@ Due to the presence of a negative cycle, for $n$ iterations of the algorithm, th d[e.b] = max(-INF, d[e.a] + e.cost); ``` -The above implementation looks for a negative cycle reachable from some starting vertex $v$; however, the algorithm can be modified to just looking for any negative cycle in the graph. For this we need to put all the distance $d[i]$ to zero and not infinity — as if we are looking for the shortest path from all vertices simultaneously; the validity of the detection of a negative cycle is not affected. +The above implementation looks for a negative cycle reachable from some starting vertex $v$; however, the algorithm can be modified to just look for any negative cycle in the graph. For this we need to put all the distance $d[i]$ to zero and not infinity — as if we are looking for the shortest path from all vertices simultaneously; the validity of the detection of a negative cycle is not affected. For more on this topic — see separate article, [Finding a negative cycle in the graph](finding-negative-cycle-in-graph.md). From 5dbf37a9f277e19636f1e740e8befc421c19aa25 Mon Sep 17 00:00:00 2001 From: Aleksandr Mishukhin <100044766+aleksmish@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:31:43 +0300 Subject: [PATCH 85/86] fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed from "then  u  must have been insert in the queue" to "then  u  must have been inserted into the queue" --- src/graph/01_bfs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graph/01_bfs.md b/src/graph/01_bfs.md index 5d7aee6f4..68a4a01c9 100644 --- a/src/graph/01_bfs.md +++ b/src/graph/01_bfs.md @@ -42,7 +42,7 @@ while (!q.empty()) { We can notice that the difference between the distances between the source `s` and two other vertices in the queue differs by at most one. Especially, we know that $d[v] \le d[u] \le d[v] + 1$ for each $u \in Q$. The reason for this is, that we only add vertices with equal distance or with distance plus one to the queue during each iteration. -Assuming there exists a $u$ in the queue with $d[u] - d[v] > 1$, then $u$ must have been insert in the queue via a different vertex $t$ with $d[t] \ge d[u] - 1 > d[v]$. +Assuming there exists a $u$ in the queue with $d[u] - d[v] > 1$, then $u$ must have been inserted into the queue via a different vertex $t$ with $d[t] \ge d[u] - 1 > d[v]$. However this is impossible, since Dijkstra's algorithm iterates over the vertices in increasing order. This means, that the order of the queue looks like this: From 3e7d29f38b20fcfec77ece36c6519da324b9adb5 Mon Sep 17 00:00:00 2001 From: Cecilia Chan <75919064+ceciliachan1979@users.noreply.github.com> Date: Sat, 13 Sep 2025 13:34:18 -0700 Subject: [PATCH 86/86] Clarify definition of opt(i, j): choose maximum k among optimal candidates # Clarify definition of `opt(i, j)` to specify maximum `k` among optimal candidates ## Description This PR updates the documentation to clarify the definition of `opt(i, j)`: - Previously, it was ambiguous when multiple values of `k` achieved the optimum. - The reference explicitly states that we should take the **maximum** value of `k` among all optimal candidates. - This change makes the intended behavior explicit and avoids confusion in implementations. ## Motivation Clarifying this definition ensures consistency with the reference and prevents misinterpretation when different values of `k` yield the same optimum. ## Changes - Clarified wording in `opt(i, j)` definition. - Specified that the chosen `k` must be the maximum among all optimal candidates. > The reference is https://dl.acm.org/doi/pdf/10.1145/800141.804691, specifically, when we define $K_c$ on the left column. --- src/dynamic_programming/knuth-optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynamic_programming/knuth-optimization.md b/src/dynamic_programming/knuth-optimization.md index 35978b839..e873732d6 100644 --- a/src/dynamic_programming/knuth-optimization.md +++ b/src/dynamic_programming/knuth-optimization.md @@ -13,7 +13,7 @@ The Speedup is applied for transitions of the form $$dp(i, j) = \min_{i \leq k < j} [ dp(i, k) + dp(k+1, j) + C(i, j) ].$$ -Similar to [divide and conquer DP](./divide-and-conquer-dp.md), let $opt(i, j)$ be the value of $k$ that minimizes the expression in the transition ($opt$ is referred to as the "optimal splitting point" further in this article). The optimization requires that the following holds: +Similar to [divide and conquer DP](./divide-and-conquer-dp.md), let $opt(i, j)$ be the maximum value of $k$ that minimizes the expression in the transition ($opt$ is referred to as the "optimal splitting point" further in this article). The optimization requires that the following holds: $$opt(i, j-1) \leq opt(i, j) \leq opt(i+1, j).$$