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