diff --git a/algorithms/graph/floyd_warshall.cpp b/algorithms/graph/floyd_warshall.cpp index 528d1a667a774ef04c7e5611b28224026ff24331..64e0c47773116bd089ae0f85a28bf86d42ba47b7 100644 --- a/algorithms/graph/floyd_warshall.cpp +++ b/algorithms/graph/floyd_warshall.cpp @@ -2,25 +2,21 @@ /// /// Time: O(V^3) /// Space: O(V^2) +/// +/// Caution: +/// - If the edge $\{v,u\}$ doesn't exist, then graph[v][u] must be inf. int dist[MAX][MAX]; int graph[MAX][MAX]; -struct FloydWarshall { - int N; - - FloydWarshall(int N) : - N(N) {} +void floyd_warshall(int n) { + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + dist[i][j] = graph[i][j]; - void run() { - for (int i = 0; i < N; ++i) - for (int j = 0; j < N; ++j) - dist[i][j] = graph[i][j]; - - for (int k = 0; k < N; ++k) - for (int i = 0; i < N; ++i) - for (int j = 0; j < N; ++j) - dist[i][j] = min(dist[i][j], - dist[i][k] + dist[k][j]); - } -}; + for (int k = 0; k < n; ++k) + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + dist[i][j] = min(dist[i][j], + dist[i][k] + dist[k][j]); +} diff --git a/algorithms/graph/steiner_tree.cpp b/algorithms/graph/steiner_tree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8dcd3d011029c3dfe220b177f5f3e3b12d917ce2 --- /dev/null +++ b/algorithms/graph/steiner_tree.cpp @@ -0,0 +1,51 @@ +/// Steiner Tree +/// +/// Description: +/// A (minimum) Steiner tree is a tree that, given a graph G and a set of +/// terminal vertices T (inside the graph), connects all vertices in T using +/// other vertices in G if necessary, minimizing the sum of weights of the +/// included edges. \par +/// The algorithm works by using dynamic programming, where dp[i][mask] +/// stores the value of a Steiner tree rooted at $i$ containing the terminal +/// nodes represented by the bits in bitmask. The algorithm iterates over all +/// bitmasks, and at each iteration $mask$ every pair of complementary subsets +/// are tested and dp[i][mask] is updated with the value given by the +/// combination of both trees. Then, still at step $mask$, dp[j][mask] is +/// updated for every $j$ with the ``extension'' of $i$ (for every $i$), as if +/// the root was moving around. \par +/// The result must be retrieved from a node (root of the final Steiner tree) +/// that contains all terminal nodes and has the smallest value. +/// +/// Time: O(n^2 * 2^t + n * 3^t) +/// Space: O(n * 2^t + n^2) +/// +/// Status: Tested (URI2885) + +int dist[MAXN][MAXN]; +int graph[MAXN][MAXN]; +int dp[MAXN][1 << MAXT]; + +int steiner_tree(int n, int t) { + floyd_warshall(n); + + fill(dp[0], dp[0] + MAXN * (1 << MAXT), inf); + for (int i = 0; i < t; ++i) + dp[i][1 << i] = 0; + + for (int mask = 1; mask < (1 << t); ++mask) { + for (int i = 0; i < n; ++i) + for (int ss = mask; ss > 0; smask = (ss - 1) & mask) + dp[i][mask] = min(dp[i][mask], + dp[i][ss] + dp[i][mask ^ ss]); + + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + dp[j][mask] = min(dp[j][mask], + dp[i][mask] + dist[i][j]); + } + + int ans = inf; + for (int i = 0; i < n; ++i) + ans = min(ans, dp[i][(1 << t) - 1]); + return ans; +} diff --git a/algorithms/math/big_integer.cpp b/algorithms/math/big_integer.cpp index ae2bed3770f6ccfdff791dd76aaa93c0a024f72c..e2fed1ae433427cf402759cb28cab6686577e200 100644 --- a/algorithms/math/big_integer.cpp +++ b/algorithms/math/big_integer.cpp @@ -3,7 +3,10 @@ /// Space: O(n) /// /// Status: Tested (KRAKOVIA) -/// Caution: Just use python. +// +/// Caution: +/// - Just use python. +// /// Include: /// - math/karatsuba diff --git a/algorithms/math/extended_euclidean.cpp b/algorithms/math/extended_euclidean.cpp index 9697789e9116688d063582983f1f66dff8871b0a..85412b10371e71a97a65d4cdfd64f2e4f68e36a1 100644 --- a/algorithms/math/extended_euclidean.cpp +++ b/algorithms/math/extended_euclidean.cpp @@ -10,7 +10,7 @@ int ext_gcd(int a, int b, int &x, int &y) { } int x1, y1; - int g = ext_gct(b % a, a, x1, y1); + int g = ext_gcd(b % a, a, x1, y1); x = y1 - (b / a) * x1; y = x1; diff --git a/algorithms/math/gale_shapley.cpp b/algorithms/math/gale_shapley.cpp index 6009274b8ffcc675b34e5a65f9d3e708d52c308f..f6d38b5285cf3edcfd33e9459461ba1a08377cd8 100644 --- a/algorithms/math/gale_shapley.cpp +++ b/algorithms/math/gale_shapley.cpp @@ -10,14 +10,17 @@ /// of men; 3) all rejected men propose to their next choice; 4) the woman /// replaces their current pair in case a man with a higher rank proposes to /// her, the replaced men are now marked as rejected; 5) repeat step 3 until -/// all men are paired. +/// all men are paired. \par +/// The result is garanteed to return a configuration where every man gets +/// the best possible wife, while every woman gets the worst possible husband +/// (it benefits the group that chooses first). /// /// Time: O(n^2) /// Space: O(n^2) /// /// Caution: -/// - Men are indexed by [0..N) -/// - Women are indexed by [N..2N) +/// - Men are indexed by $[0,N)$ +/// - Women are indexed by $[N,2N)$ /// - The result prioritizes men, swapping the bottom half /// of the matrix by the top half will invert who's given /// preference @@ -31,11 +34,11 @@ vector<int> gale_shapley(const vector<vector<int>> &pref) { vector<int> w_part(n, -1); vector<int> m_part(n, -1); vector<int> start(n, 0); - + while (true) { int m; for (m = 0; m < n; ++m) - if (m_part[m] == -1) + if (m_part[m] == -1) break; if (m == n) break; diff --git a/algorithms/structure/segment_tree.cpp b/algorithms/structure/segment_tree.cpp index 77f82655b21bf2de8195f4f6c07de1a88dc54875..b889aae5ab41c692467945c4471b2f7ce3917e65 100644 --- a/algorithms/structure/segment_tree.cpp +++ b/algorithms/structure/segment_tree.cpp @@ -6,7 +6,7 @@ /// Space: O(n) /// /// Caution: -/// - Query returns op([l..r)) +/// - Query returns $op([l,r))$ /// - Provide identity value if necessary (default is T()) // Example: SegmentTree<int,plus<int>> seg(n) diff --git a/caderno.pdf b/caderno.pdf index 0be09685d4ca6d5c8ad92e21ee518a0f3077b01d..b7acedaa4c089045a0c2991694d6e10e389c19bf 100644 Binary files a/caderno.pdf and b/caderno.pdf differ diff --git a/contests/SBC18/J.cpp b/contests/SBC18/J.cpp index 51e09ec3b0b26cd28ba4d53794eaac9aabc35e8f..9401290795e10f308d23125f3a93bef54cd9c8ce 100644 --- a/contests/SBC18/J.cpp +++ b/contests/SBC18/J.cpp @@ -1,14 +1,12 @@ #include <bits/stdc++.h> -#define MAX 0 -#define MOD 1000000007 #define EPS 1e-6 +#define MOD 1000000007 #define inf 0x3f3f3f3f #define llinf 0x3f3f3f3f3f3f3f3f #define fi first #define se second -#define sz size() #define pb push_back #define ende '\n' @@ -18,18 +16,43 @@ using namespace std; -typedef long long ll; -typedef pair<int,int> ii; +using ll = long long; +using ii = pair<int,int>; + +double graph[101][101]; +double dp[101][2100]; int main() { ios::sync_with_stdio(0); cin.tie(0); + cout << setprecision(5) << fixed; int n, k; cin >> n >> k; - for (int i = 0; i < n; ++i) { - double x, y; - cin >> x >> y; + vector<double> x(n), y(n); + for (int i = 0; i < n; ++i) + cin >> x[i] >> y[i]; + + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + graph[i][j] = hypot(x[i] - x[j], y[i] - y[j]); + + fill(dp[0], dp[0] + 101 * 2100, 1e9); + for (int i = 0; i < k; ++i) + dp[i][1<<i] = 0; + + for (int mask = 0; mask < (1 << k); ++mask) { + for (int i = 0; i < n; ++i) + for (int ss = mask; ss > 0; ss = (ss - 1) & mask) + dp[i][mask] = min(dp[i][mask], dp[i][ss] + dp[i][mask - ss]); + + for (int i = 0; i < n; ++i) + for (int j = k; j < n; ++j) + dp[j][mask] = min(dp[j][mask], dp[i][mask] + graph[i][j]); } - + + double ans = 1e9; + for (int i = k; i < n; ++i) + ans = min(ans, dp[i][(1 << k) - 1]); + cout << ans << ende; return 0; } diff --git a/notebook/gen_latex.py b/notebook/gen_latex.py index 4871f39d0754c646f75765d1c458260d8533fe6c..01a79e8825fbbff5d28765507559695407b9e1b2 100644 --- a/notebook/gen_latex.py +++ b/notebook/gen_latex.py @@ -112,14 +112,6 @@ class LatexGenerator: # Writes own header to LaTeX output. def output_header(self, write): - if len(self.header) > 0: - write('\\begin{adjustwidth}{5pt}{5pt}\n') - - if 'Description' in self.header: - write('\\textbf{\\footnotesize Description: }\n') - write('\\footnotesize{\\par %s}' % self.header['Description']) - write('\\\\\n') - write('~\\\\\n') # Replaces text with LaTeX on Big-O notations. def to_big_o(expr): @@ -131,26 +123,65 @@ class LatexGenerator: # Outputs time or space complexity. def output_complexity(comp): - if comp in self.header: - write('\\textbf{\\footnotesize %s: }' % comp) - if len(self.header[comp]) > 1: - write('\n') - write('\\begin{compactitem}\n') - for i in self.header[comp]: - line = i[1:].split(':') - write('\\item{\\footnotesize{%s: $%s$}}\n' % - (line[0].strip().replace('_', '\\_'), - to_big_o(line[1].strip()))) - write('\\end{compactitem}\n') - else: - write('\\footnotesize{$%s$}\n' % - to_big_o(self.header[comp][0])) - return True - return False - - if output_complexity('Time'): - write('~\\\\\n') - output_complexity('Space') + write('\\textbf{\\footnotesize %s: }' % comp) + if len(self.header[comp]) > 1: + write('\n') + write('\\begin{compactitem}\n') + for i in self.header[comp]: + line = i[1:].split(':') + write('\\item{\\footnotesize{%s: $%s$}}\n' % + (line[0].strip().replace('_', '\\_'), + to_big_o(line[1].strip()))) + write('\\end{compactitem}') + else: + write('\\footnotesize{$%s$}\n' % + to_big_o(self.header[comp][0])) + + if len(self.header) > 0: + write('\\begin{adjustwidth}{5pt}{5pt}\n') + + has_previous = False + if 'Description' in self.header: + write('\\textbf{\\footnotesize Description: }\n') + write('\\footnotesize{\\par %s}' % self.header['Description']) + write('\\\\\n') + has_previous = True + + if 'Time' in self.header: + if has_previous: + write('~\\\\\n') + output_complexity('Time') + has_previous = True + + if 'Space' in self.header: + if has_previous: + write('~\\\\\n') + output_complexity('Space') + has_previous = True + + if 'Caution' in self.header: + if has_previous: + write('\\\\\n') + write('~\\\\\n') + if len(self.header['Caution']) > 0: + write('\\textbf{\\footnotesize Caution: }\n') + write('\n') + write('\\begin{compactitem}\n') + current = [] + for i in self.header['Caution']: + sep = i.split() + if sep[0] == '-': + if len(current) > 0: + write('\\item{\\footnotesize %s}' % ' '.join(current)) + current = [] + else: + current += [ ' '.join(sep[1:]) ] + else: + current += [ i ] + + if len(current) > 0: + write('\\item{\\footnotesize %s}' % ' '.join(current)) + write('\\end{compactitem}\n') if len(self.header) > 0: write('\\end{adjustwidth}\n')