From 99a6176affac4084790adbef0ed2d4e8a4d35431 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 7 Apr 2016 07:45:04 +0900 Subject: [PATCH 001/141] Boolean matrix --- math/matrix_bool.cc | 53 ++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/math/matrix_bool.cc b/math/matrix_bool.cc index f338d07..0b44559 100644 --- a/math/matrix_bool.cc +++ b/math/matrix_bool.cc @@ -23,7 +23,6 @@ using namespace std; -// proposed namespace bitmatrix { typedef unsigned long long ull; struct mat { @@ -58,25 +57,22 @@ mat add(mat A, const mat &B) { A.x[i][j] |= B.x[i][j]; return A; } + +void disp(ull a) { + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 8; ++j) { + printf("%d", !!(a & 1)); + a >>= 1; + } + printf("\n"); + } +} + ull mul(ull a, ull b) { // C[i][j] |= A[i][k] & B[k][j] - const ull u = 0x101010101010101, v = 0xff; - ull x, y, c = 0; - x = a&(u<< 0); x |= (x<<1); x |= (x<< 2); x |= (x << 4); - y = b&(v<< 0); y |= (y<<8); y |= (y<<16); y |= (y <<32); c |= (x&y); - x = a&(u<< 1); x |= (x>>1); x |= (x<< 2); x |= (x << 4); - y = b&(v<<18); y |= (y>>8); y |= (y<<16); y |= (y <<32); c |= (x&y); - x = a&(u<< 2); x |= (x<<1); x |= (x>> 2); x |= (x << 4); - y = b&(v<<16); y |= (y<<8); y |= (y>>16); y |= (y <<32); c |= (x&y); - x = a&(u<< 3); x |= (x>>1); x |= (x>> 2); x |= (x << 4); - y = b&(v<<24); y |= (y>>8); y |= (y>>16); y |= (y <<32); c |= (x&y); - x = a&(u<< 4); x |= (x<<1); x |= (x<< 2); x |= (x >> 4); - y = b&(v<<32); y |= (y<<8); y |= (y<<16); y |= (y >>32); c |= (x&y); - x = a&(u<< 5); x |= (x>>1); x |= (x<< 2); x |= (x >> 4); - y = b&(v<<40); y |= (y>>8); y |= (y<<16); y |= (y >>32); c |= (x&y); - x = a&(u<< 6); x |= (x<<1); x |= (x>> 2); x |= (x >> 4); - y = b&(v<<48); y |= (y<<8); y |= (y>>16); y |= (y >>32); c |= (x&y); - x = a&(u<< 7); x |= (x>>1); x |= (x>> 2); x |= (x >> 4); - y = b&(v<<56); y |= (y>>8); y |= (y>>16); y |= (y >>32); c |= (x&y); + const ull u = 0xff, v = 0x101010101010101; + ull c = 0; + for (;a && b; a >>= 1, b >>= 8) + c |= (((a & v) * u) & ((b & u) * v)); return c; } mat mul(mat A, mat B) { @@ -108,7 +104,7 @@ ull transpose(ull a) { mat transpose(mat A) { mat B(A.m, A.n); for (int i = 0; i < A.x.size(); ++i) - for (int j = 0; j < A.x[0].size(); ++j) + for (int j = 0; j <= A.x[0].size(); ++j) B.x[j][i] = transpose(A.x[i][j]); return B; } @@ -149,9 +145,8 @@ mat pow(mat A, int k) { } } -/* int main() { - for (int n = 1; n < 512; n *= 2) { + for (int n = 1; n < 10000; n *= 2) { printf("%d\t", n); { using namespace bitmatrix; @@ -166,6 +161,8 @@ int main() { _time = clock() - _time; printf("%f\t", _time / CLOCKS_PER_SEC); } + printf("\n"); + continue; { using namespace vector_bool; mat A(n, vec(n)); @@ -182,15 +179,3 @@ int main() { } } } -*/ -int main() { - using namespace bitmatrix; - int n = 12; - mat A(n,n); - for (int i = 0; i < n; ++i) - for (int j = 0; j < n; ++j) - A.set(i, j, rand() % 2); - - cout << A << endl; - cout << transpose(A) << endl; -} From e7f0004097eaac0e929db31fae8ab21c968cad4e Mon Sep 17 00:00:00 2001 From: Xiaohui Wang Date: Thu, 7 Apr 2016 22:42:19 -0400 Subject: [PATCH 002/141] Minimum coin change (dynamic programming --- dynamic_programming/minimum_coin_change.cc | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 dynamic_programming/minimum_coin_change.cc diff --git a/dynamic_programming/minimum_coin_change.cc b/dynamic_programming/minimum_coin_change.cc new file mode 100644 index 0000000..179532f --- /dev/null +++ b/dynamic_programming/minimum_coin_change.cc @@ -0,0 +1,62 @@ +// Minimum Coin Change problem (Dynamic Programming) +// Description: +// Given an infinite supply of valued coins {c1, c2, c3, ... cn} and a value N +// Output the minimum number of coins to make the change + +// Algorithm: +// Construct a table[][] and solve in a top bottom manner. +// The witness pred[] array records the coins that are selected. + +// Complexity: +// For m number of coins and n amount of money: +// O(mn) for time +// O(n) for space + +#include +#include +#include +#include + +using namespace std; + +// find the minimum number of coin changes and print the witness +int coin_change(int coins[], int cn, int money){ + int table[money+1]; + table[0] = 0; + int pred[money+1]; + for (int i=0; i<=money;i++){ + pred[i] = 0; + } + for (int j=1; j<=money;j++){ + table[j] = INT_MAX; + } + for (int i=1;i<=money;i++){ + int mini = table[i]; + for (int j=0; j= coins[j]){ + mini = min(mini, table[i-coins[j]]+1); + pred[i] = j; + } + } + table[i] = mini; + } + int m = money; + while (m != 0){ + cout<<"change coin: "< Date: Thu, 7 Apr 2016 22:45:39 -0400 Subject: [PATCH 003/141] Minimum Coin Change (Dynamic Programming) --- dynamic_programming/minimum_coin_change.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic_programming/minimum_coin_change.cc b/dynamic_programming/minimum_coin_change.cc index 179532f..b11f3a2 100644 --- a/dynamic_programming/minimum_coin_change.cc +++ b/dynamic_programming/minimum_coin_change.cc @@ -36,7 +36,7 @@ int coin_change(int coins[], int cn, int money){ if (i >= coins[j]){ mini = min(mini, table[i-coins[j]]+1); pred[i] = j; - } + } } table[i] = mini; } From 204b1cef4fc7f53f7f24ca840efcfd2e2f89f0be Mon Sep 17 00:00:00 2001 From: Xiaohui Wang Date: Thu, 7 Apr 2016 23:45:07 -0400 Subject: [PATCH 004/141] Rod Cutting (dynamic programming) --- dynamic_programming/minimum_coin_change.cc | 2 +- dynamic_programming/rod_cutting.cc | 65 ++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 dynamic_programming/rod_cutting.cc diff --git a/dynamic_programming/minimum_coin_change.cc b/dynamic_programming/minimum_coin_change.cc index b11f3a2..179532f 100644 --- a/dynamic_programming/minimum_coin_change.cc +++ b/dynamic_programming/minimum_coin_change.cc @@ -36,7 +36,7 @@ int coin_change(int coins[], int cn, int money){ if (i >= coins[j]){ mini = min(mini, table[i-coins[j]]+1); pred[i] = j; - } + } } table[i] = mini; } diff --git a/dynamic_programming/rod_cutting.cc b/dynamic_programming/rod_cutting.cc new file mode 100644 index 0000000..441e164 --- /dev/null +++ b/dynamic_programming/rod_cutting.cc @@ -0,0 +1,65 @@ +// Rod Cutting Problem + +#include +#include + +using namespace std; + +// output the maximum values we can get +int rod_cut(int v[], int vsize, int len){ + int values[len+1]; + values[0] = 0; + int cur_max; + for (int i=1; i<=len; i++){ + cur_max = -1; + for (int j=1; j<=i; j++){ + if (j cur_max){ + cur_max = values[i-j] + v[j]; + } + } + values[i] = cur_max; + } + return values[len]; +} + +// output the patterns of cutting that can generates the maximum value +int* rod_cutting_witness(int v[], int vsize, int len){ + int values[len+1]; + values[0] = 0; + int cur_max; + int *witness = new int [len+1]; + witness[0] = 0; + for (int i=1; i<=len; i++){ + cur_max = -1; + for (int j=1; j<=i; j++){ + if (j cur_max){ + cur_max = values[i-j]+v[j]; + values[i] = cur_max; + witness[i] = j; + } + } + } + int m = len; + while (m != 0){ + if (witness[m] < m){ + cout<<"cut: "< Date: Fri, 8 Apr 2016 17:51:56 -0400 Subject: [PATCH 005/141] Rod cutting (dynamic programming) --- dynamic_programming/rod_cutting.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dynamic_programming/rod_cutting.cc b/dynamic_programming/rod_cutting.cc index 441e164..2cf3908 100644 --- a/dynamic_programming/rod_cutting.cc +++ b/dynamic_programming/rod_cutting.cc @@ -1,4 +1,15 @@ // Rod Cutting Problem +// Description: +// Given an array of values and a rod length, find the maximum value we can get by doing the rod cutting +// Algorithm: +// let di denotes the maximum value we can get from cutting a rod of length i, vi denotes the value of a cut of length i +// then +// di = 0, when i = 0; +// di = max(di-k + vk) for 1<=k<=i, when i>=1 +// Complexity: +// let m be the number of different kinds of cut, let n be the rod length +// time complexity: O(mn) +// Space complexity: O(n) #include #include @@ -23,6 +34,8 @@ int rod_cut(int v[], int vsize, int len){ } // output the patterns of cutting that can generates the maximum value +// pred[] keeps track of the cut of each length +// pred[i] denotes the cut made when the rod length is i int* rod_cutting_witness(int v[], int vsize, int len){ int values[len+1]; values[0] = 0; From 475521434cbadba1d0a9cfcc3588e90452605568 Mon Sep 17 00:00:00 2001 From: Xiaohui Wang Date: Fri, 8 Apr 2016 18:34:40 -0400 Subject: [PATCH 006/141] minimum_coin_change (dynamic programming) --- dynamic_programming/minimum_coin_change.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dynamic_programming/minimum_coin_change.cc b/dynamic_programming/minimum_coin_change.cc index 179532f..fc453f9 100644 --- a/dynamic_programming/minimum_coin_change.cc +++ b/dynamic_programming/minimum_coin_change.cc @@ -6,6 +6,10 @@ // Algorithm: // Construct a table[][] and solve in a top bottom manner. // The witness pred[] array records the coins that are selected. +// define d[i] as the minimum number of coins to change i amout of money, cj as the coin value of jth coin +// then +// d[i] = 0, when i=0 +// d[i] = min(d[i], d[i-cj]+1) for cj<=i, when i>=1 // Complexity: // For m number of coins and n amount of money: From 1943651adfb711c9ace8e8b0b4ea493067547bf3 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 1 Jun 2016 00:00:17 +0900 Subject: [PATCH 007/141] Traveling Salesman Problem (branch-and-bound) --- other/traveling_salesman_problem.cc | 232 ++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 other/traveling_salesman_problem.cc diff --git a/other/traveling_salesman_problem.cc b/other/traveling_salesman_problem.cc new file mode 100644 index 0000000..da2633e --- /dev/null +++ b/other/traveling_salesman_problem.cc @@ -0,0 +1,232 @@ +// +// Traveling Salesman Problem (Branch-and-Bound) +// +// Description: +// It finds TSP by branch-and-bound algorithm that computes +// a lower bound from the reduced cost matrix. +// This procedure is similar to the Kuhn-Munkres algorithm. +// +// In practice, it scales to networks with |V| <= 40. +// +// +// References: +// J. D. C. Little, K. G. Murty, D. W. Sweeney, and C. Karel (1963): +// An algorithm for traveling salesman problem. +// Operations Research, vol. 11, pp. 972--989. +// +// Verified: +// AOJ DPL_2_A: Traveling Salesman Problem + +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +const double INF = 1.0 / 0.0; +struct traveling_salesman_problem { + int n; + vector> w; // set solver.w[i][j] = infty, etc + traveling_salesman_problem(int n) : n(n), w(n, vector(n, INF)) { } + + double dynamic_programming() { + vector> c(n, vector(1<> p(n, vector(1< c[i][S] + w[i][j]) { + c[j][S|(1< c[i][(1< path(n); + int S = (1 << n) - 1; + path[n-1] = last; + for (int i = n-1; i >= 1; --i) { + path[i-1] = p[path[i]][S]; + S ^= (1 << path[i]); + } + return ans; + } + double brute_force() { + vector tour; + for (int i = 0; i < n; ++i) + tour.push_back(i); + double ans = INF; + do { + double cost = 0; + for (int i = 0; i < tour.size(); ++i) { + cost += w[tour[i]][tour[(i+1)%n]]; + } + ans = min(ans, cost); + } while (next_permutation(tour.begin()+1, tour.end())); + return ans; + } + + vector next, prev, best; + double upper_bound; + void explore(int edges, double cost, vector row, vector col) { + int size = row.size(); + vector rowred(size, INF), colred(size, INF); + for (int i = 0; i < size; ++i) { + for (int j = 0; j < size; ++j) + rowred[i] = min(rowred[i], w[row[i]][col[j]]); + for (int j = 0; j < size; ++j) + if (w[row[i]][col[j]] < INF) + w[row[i]][col[j]] -= rowred[i]; + cost += rowred[i]; + } + for (int j = 0; j < size; ++j) { + for (int i = 0; i < size; ++i) + colred[j] = min(colred[j], w[row[i]][col[j]]); + for (int i = 0; i < size; ++i) + if (w[row[i]][col[j]] < INF) + w[row[i]][col[j]] -= colred[j]; + cost += colred[j]; + } + if (cost < upper_bound) { + if (edges == n - 2) { + upper_bound = cost; + best = next; + best[row[0]] = col[0]; + best[row[1]] = col[1]; + if (w[row[0]][col[0]] >= INF) + swap(best[row[0]], best[row[1]]); + } else { + int r, c; + double most = -INF; + for (int i = 0; i < size; ++i) { + for (int j = 0; j < size; ++j) { + if (w[row[i]][col[j]] != 0) continue; + double minrow = INF, mincol = INF; + for (int k = 0; k < size; ++k) { + if (i != k) minrow = min(minrow, w[row[k]][col[j]]); + if (j != k) mincol = min(mincol, w[row[i]][col[k]]); + } + if (most < minrow + mincol) { + most = minrow + mincol; + r = i; + c = j; + } + } + } + next[row[r]] = col[c]; + prev[col[c]] = row[r]; + + int last = col[c], first = row[r]; + while (next[last] >= 0) last = next[last]; + while (prev[first] >= 0) first = prev[first]; + double colrowval = w[last][first]; + w[last][first] = INF; + vector newrow = row, newcol = col; + newrow.erase(newrow.begin() + r); + newcol.erase(newcol.begin() + c); + explore(edges + 1, cost, newrow, newcol); + w[last][first] = colrowval; + + prev[col[c]] = -1; + next[row[r]] = -1; + + if (cost + most < upper_bound) { + w[row[r]][col[c]] = INF; + explore(edges, cost, row, col); + w[row[r]][col[c]] = 0; + } + } + } + for (int i = 0; i < size; ++i) + for (int j = 0; j < size; ++j) + w[row[i]][col[j]] += rowred[i] + colred[j]; + } + + double solve() { + vector row(n), col(n); + for (int i = 0; i < n; ++i) row[i] = col[i] = i; + upper_bound = INF; + prev = next = vector(n, -1); + explore(0, 0, row, col); + + if (upper_bound < INF) { + vector path(n); // solution + path[0] = 0; + for (int i = 1; i < n; ++i) + path[i] = best[path[i-1]]; + } + return upper_bound; + } +}; + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +/* +int main() { + for (int iter = 0; iter < 1000; ++iter) { + srand(iter); + int n = 40; + traveling_salesman_problem tsp(n); + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + if (i != j) tsp.w[i][j] = rand() % 1000 + 1; + + tick(); + double a = 0;// tsp.brute_force(); + double ta = tick(); + double b = 0;// tsp.dynamic_programming(); + double tb = tick(); + double c = tsp.solve(); + double tc = tick(); + + a = b =c; + printf("%f %f\n%f %f\n%f %f\n\n", a, ta, b, tb, c, tc); + if (a != b || b != c) { + printf("seed = %d\n", iter); + exit(-1); + } + } +} +*/ + +// AOJ: DPL_2_A +int main() { + int n, m; + scanf("%d %d", &n, &m); + traveling_salesman_problem tsp(n); + for (int i = 0; i < m; ++i) { + int u, v, w; + scanf("%d %d %d", &u, &v, &w); + tsp.w[u][v] = w; + } + double ans = tsp.solve(); + if (ans < INF) printf("%.0f\n", ans); + else printf("-1\n"); +} From 6f2c3f1896cb116f550acefb9ad429bc398909a5 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 1 Jun 2016 22:14:21 +0900 Subject: [PATCH 008/141] Zero-One IP solver (Balas's additive branch-and-bound) --- math/zerooneIPsolver.cc | 172 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 math/zerooneIPsolver.cc diff --git a/math/zerooneIPsolver.cc b/math/zerooneIPsolver.cc new file mode 100644 index 0000000..3c2e24d --- /dev/null +++ b/math/zerooneIPsolver.cc @@ -0,0 +1,172 @@ +// +// Zero-One IP Solver +// +// Description: +// Balas's additive IP sovler branch-and-bound IP solver. +// It seeks an integer solution to min c'x s.t. Ax <= b, x in {0,1}^n. +// The algorithm enumerates x with some branch-and-bound techniques +// without solving the corresponding LP. +// +// It scales about n <= 30. +// +// +// References: +// E. Balas (1965): +// An additive algorithm for solving linear programs with zero-one variables. +// Operations Research, vol. 13, no. 4, pp. 517--546. +// +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +bool next_radix(It begin, It end, int base) { + for (It cur = begin; cur != end; ++cur) { + if ((*cur += 1) >= base) *cur = 0; + else return true; + } + return false; +} + + +const double INF = 1.0 / 0.0; + +struct ip_solve { + int m, n; + vector c, b; + vector> A; + + double gauge; + vector neg; + ip_solve(vector c, vector> A, vector b) : + m(b.size()), n(c.size()), c(c), b(b), A(A), gauge(0), neg(n) { + // normalize c[j] >= 0 + for (int j = 0; j < n; ++j) { + if (c[j] >= 0) continue; + neg[j] = 1; + gauge += c[j]; + c[j] = -c[j]; + for (int i = 0; i < m; ++i) { + b[i] -= A[i][j]; + A[i][j] = -A[i][j]; + } + } + } + + double obj; + vector x, sol; + void explore(double cost) { + vector history; + + int negatives = 0; + for (int i = 0; i < m; ++i) { + if (b[i] >= 0) continue; + ++negatives; + double residual = b[i]; + double bound = cost; + double except = -INF; + + for (int j = 0; j < n; ++j) { + if (x[j] >= 0) continue; + if (c[j] + cost >= obj) { + history.push_back(j); + x[j] = 0; + } else if (A[i][j] < 0) { + residual -= A[i][j]; + bound += c[j]; + except = max(except, A[i][j]); + } + } + if (residual < 0) { negatives = -1; break; } + if (residual + except < 0) { + if (bound >= obj) { negatives = -1; break; } + for (int j = 0; j < n; ++j) { + if (x[j] < 0 && A[i][j] < 0) { + history.push_back(j); + x[j] = 1; + cost += c[j]; + for (int i = 0; i < m; ++i) + b[i] -= A[i][j]; + } + } + } + } + if (negatives == 0) { + obj = cost; + for (int j = 0; j < n; ++j) + sol[j] = max(0, x[j]); + } else if (negatives > 0) { + int p = -1; + double min_infeasibility = -INF, min_cost = INF; + for (int j = 0; j < n; ++j) { + if (x[j] >= 0) continue; + double infeasibility = 0; + for (int i = 0; i < m; ++i) + infeasibility += min(0.0, b[i] - A[i][j]); + if (infeasibility > min_infeasibility || + (infeasibility == min_infeasibility && c[j] < min_cost)) { + min_cost = c[j]; + min_infeasibility = infeasibility; + p = j; + } + } + if (p >= 0) { + x[p] = 1; + for (int i = 0; i < m; ++i) b[i] -= A[i][p]; + explore(cost + c[p]); + x[p] = 0; + for (int i = 0; i < m; ++i) b[i] += A[i][p]; + explore(cost); + x[p] = -1; + } + } + for (int j: history) { + if (x[j] == 1) { + for (int i = 0; i < m; ++i) + b[i] += A[i][j]; + } + x[j] = -1; + } + } + + void solve() { + obj = INF; + x = sol= vector(n, -1); + explore(0); + obj += gauge; + for (int i = 0; i < n; ++i) + sol[i] ^= neg[i]; + } +}; + +int main() { + int n = 50, m = 20; + vector c(n, 1); + + for (int i = 0; i < n; ++i) + c[i] = rand() % 11 - 5; + + vector b(m, -1); + + for (int i = 0; i < m; ++i) + b[i] = rand() % 11 - 5; + + vector> A(m, vector(n)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) + A[i][j] = rand() % 11 - 5; + } + + ip_solve solver(c, A, b); + solver.solve(); + printf("%.0f\n", solver.obj); +} From 4664e9146347b2ff458847c9ba5c38a5e93b16ac Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 1 Jun 2016 22:32:45 +0900 Subject: [PATCH 009/141] Balas' zero-one IP solver --- math/{zerooneIPsolver.cc => zero_one_IP_solver.cc} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename math/{zerooneIPsolver.cc => zero_one_IP_solver.cc} (98%) diff --git a/math/zerooneIPsolver.cc b/math/zero_one_IP_solver.cc similarity index 98% rename from math/zerooneIPsolver.cc rename to math/zero_one_IP_solver.cc index 3c2e24d..7d6569b 100644 --- a/math/zerooneIPsolver.cc +++ b/math/zero_one_IP_solver.cc @@ -2,7 +2,7 @@ // Zero-One IP Solver // // Description: -// Balas's additive IP sovler branch-and-bound IP solver. +// Balas's branch-and-bound 0-1 IP sovler. // It seeks an integer solution to min c'x s.t. Ax <= b, x in {0,1}^n. // The algorithm enumerates x with some branch-and-bound techniques // without solving the corresponding LP. From 425aa7dbc791a1bd61e5a36f772759675f6bfc8e Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 2 Jun 2016 07:55:33 +0900 Subject: [PATCH 010/141] Calendar (Gregorian Date) --- other/calendar.cc | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 other/calendar.cc diff --git a/other/calendar.cc b/other/calendar.cc new file mode 100644 index 0000000..27d24a4 --- /dev/null +++ b/other/calendar.cc @@ -0,0 +1,56 @@ +// +// Calendar +// +// Description: +// A code for converting gregorian date <=> julian day number +// + +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct gregorian_date { + int y, m, d; + gregorian_date(int y, int m, int d) : y(y), m(m), d(d) { } + + // from julian day number to gregorian date + gregorian_date(int x) { + int e = 4*x + 4*((((4*x+274277)/146097)*3)/4) + 5455; + int h = 5*((e% 1461) / 4) + 2; + d = (h%153)/5 + 1; + m = (h/153+2)%12 + 1; + y = (e/1461) + (14-m)/12 - 4716; + } + // number of days from the epoch + int julian_day_number() const { + int a = (14-m)/12, Y = y+4800-a, M = m+12*a-3; + return d + (153*M+2)/5 + 365*Y + (Y/4) - (Y/100) + (Y/400) - 32045; + } + // week of the day + int day_of_week() const { + return (julian_day_number() + 1) % 7; + } + bool is_leap() const { + return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; + } +}; +ostream &operator<<(ostream &os, const gregorian_date &g) { + os << g.y << "/" << g.m << "/" << g.d; + return os; +} + +int main() { + int JDN = gregorian_date(2000, 1, 1).julian_day_number(); + cout << JDN << endl; + auto g = gregorian_date(JDN); + cout << g << endl; +} From f7c3737442515ddac641a17daf3b821fb58a9dbc Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 2 Jun 2016 07:59:00 +0900 Subject: [PATCH 011/141] Reachability query --- reachability.cc => graph/reachability.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename reachability.cc => graph/reachability.cc (100%) diff --git a/reachability.cc b/graph/reachability.cc similarity index 100% rename from reachability.cc rename to graph/reachability.cc From 9ce0c6d84093fded407a1815b5b10267bde3fe32 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 2 Jun 2016 08:04:31 +0900 Subject: [PATCH 012/141] Traveling Salesman Problem (branch-and-bound) --- .../traveling_salesman.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename other/traveling_salesman_problem.cc => graph/traveling_salesman.cc (97%) diff --git a/other/traveling_salesman_problem.cc b/graph/traveling_salesman.cc similarity index 97% rename from other/traveling_salesman_problem.cc rename to graph/traveling_salesman.cc index da2633e..289d0d9 100644 --- a/other/traveling_salesman_problem.cc +++ b/graph/traveling_salesman.cc @@ -2,9 +2,9 @@ // Traveling Salesman Problem (Branch-and-Bound) // // Description: -// It finds TSP by branch-and-bound algorithm that computes -// a lower bound from the reduced cost matrix. -// This procedure is similar to the Kuhn-Munkres algorithm. +// It solves TSP exactly by branch-and-bound algorithm that +// employs a lower bound from the reduced cost matrix, +// which is similar to the Kuhn-Munkres reduction. // // In practice, it scales to networks with |V| <= 40. // From e247dc4337468bfacd2c0cc3d257ff6976dae371 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 2 Jun 2016 08:07:01 +0900 Subject: [PATCH 013/141] Next number in radix B --- combinatorics/next_radix.cc | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 combinatorics/next_radix.cc diff --git a/combinatorics/next_radix.cc b/combinatorics/next_radix.cc new file mode 100644 index 0000000..1a38dd2 --- /dev/null +++ b/combinatorics/next_radix.cc @@ -0,0 +1,38 @@ +// +// 0 0 0 +// 1 0 0 +// 2 0 0 +// 0 1 0 +// 1 1 0 +// 2 1 0 +// ... +// +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +bool next_radix(It begin, It end, int base) { + for (It cur = begin; cur != end; ++cur) { + if ((*cur += 1) >= base) *cur = 0; + else return true; + } + return false; +} + +int main() { + vector a(3, 0); + do { + for (int i = 0; i < 3; ++i) cout << a[i]; + cout << endl; + } while (next_radix(all(a), 2)); +} From c1f86cd1225a64a8f752d5e50124536b0c2a92fa Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 2 Jun 2016 08:07:25 +0900 Subject: [PATCH 014/141] Next number array in radix B --- combinatorics/next_radix.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/combinatorics/next_radix.cc b/combinatorics/next_radix.cc index 1a38dd2..b4847fa 100644 --- a/combinatorics/next_radix.cc +++ b/combinatorics/next_radix.cc @@ -19,7 +19,7 @@ using namespace std; #define snd second #define all(c) ((c).begin()), ((c).end()) #define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } - + template bool next_radix(It begin, It end, int base) { for (It cur = begin; cur != end; ++cur) { From f19ad366ad7b0182f56ba5abe5649e0ce144abbd Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 08:13:54 +0900 Subject: [PATCH 015/141] Update and rename maximum_flow_D.cc to maximum_flow_dinic.cc --- graph/{maximum_flow_D.cc => maximum_flow_dinic.cc} | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) rename graph/{maximum_flow_D.cc => maximum_flow_dinic.cc} (94%) diff --git a/graph/maximum_flow_D.cc b/graph/maximum_flow_dinic.cc similarity index 94% rename from graph/maximum_flow_D.cc rename to graph/maximum_flow_dinic.cc index e0c4785..8b637f3 100644 --- a/graph/maximum_flow_D.cc +++ b/graph/maximum_flow_dinic.cc @@ -10,6 +10,8 @@ // // Complexity: // O(n^2 m), but very fast in practice. +// In particular, for a unit capacity graph, +// it runs in O(m min{m^{1/2}, n^{2/3}}). // // Verified: // SPOJ FASTFLOW @@ -19,7 +21,7 @@ // Algorithm for solution of a problem of maximum flow in networks with power estimation. // Soviet Mathematics Doklady, vol. 11, pp. 1277-1280. // -// B. H. Korte and Jens Vygen (2008): +// B. H. Korte and J. Vygen (2008): // Combinatorial Optimization: Theory and Algorithms. // Springer Berlin Heidelberg. // @@ -49,7 +51,7 @@ struct graph { graph(int n) : n(n), adj(n) { } void add_edge(int src, int dst, long long capacity) { adj[src].push_back({src, dst, capacity, 0, adj[dst].size()}); - adj[dst].push_back({dst, src, capacity, 0, adj[src].size()-1}); + adj[dst].push_back({dst, src, capacity, 0, adj[src].size()-1}); // bidirectional edge } long long max_flow(int s, int t) { vector level(n), iter(n); From e5a0af22582a7c080eb7be5b04f2ab45b2fc91a8 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 08:14:31 +0900 Subject: [PATCH 016/141] Update README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 303a9ae..27466fd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -C++ implementations of algorithms -========= +# C++ implementations of algorithms These codes are my C++ implementations of algorithms, which are written for studying/understanding algorithms. @@ -10,3 +9,10 @@ You can use them for any purpose without any warranty. author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) + +# List + +## Graph + +- [Maximum Flow (Ford-Fulkerson)](maximum_flow_ford_fulkerson.cc) +- [Maximum Flow (Dinic)](graph/maximum_flow_dinic.cc) From 874b4b9633c090c30b68a3f67f3bd2fba620d973 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 08:15:33 +0900 Subject: [PATCH 017/141] Update and rename maximum_flow_FF.cc to maximum_flow_ford_fulkerson.cc --- graph/{maximum_flow_FF.cc => maximum_flow_ford_fulkerson.cc} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename graph/{maximum_flow_FF.cc => maximum_flow_ford_fulkerson.cc} (98%) diff --git a/graph/maximum_flow_FF.cc b/graph/maximum_flow_ford_fulkerson.cc similarity index 98% rename from graph/maximum_flow_FF.cc rename to graph/maximum_flow_ford_fulkerson.cc index 4ce76b2..7f62e1c 100644 --- a/graph/maximum_flow_FF.cc +++ b/graph/maximum_flow_ford_fulkerson.cc @@ -15,7 +15,7 @@ // AOJ GRL_6_A: Maximum Flow // // Reference: -// B. H. Korte and Jens Vygen (2008): +// B. H. Korte and J. Vygen (2008): // Combinatorial Optimization: Theory and Algorithms. // Springer Berlin Heidelberg. // From a6b5a5e7a5846c74271e972fa46f265294c8be95 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 08:16:49 +0900 Subject: [PATCH 018/141] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27466fd..9717b8f 100644 --- a/README.md +++ b/README.md @@ -14,5 +14,5 @@ author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) ## Graph -- [Maximum Flow (Ford-Fulkerson)](maximum_flow_ford_fulkerson.cc) +- [Maximum Flow (Ford-Fulkerson)](graph/maximum_flow_ford_fulkerson.cc) - [Maximum Flow (Dinic)](graph/maximum_flow_dinic.cc) From b959e6e1e421c8fea948821d42491441499ee54a Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 08:18:31 +0900 Subject: [PATCH 019/141] Traveling Salesman Problem (Little et al's Branch-and-Bound) --- graph/traveling_salesman.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graph/traveling_salesman.cc b/graph/traveling_salesman.cc index 289d0d9..324885b 100644 --- a/graph/traveling_salesman.cc +++ b/graph/traveling_salesman.cc @@ -1,5 +1,5 @@ // -// Traveling Salesman Problem (Branch-and-Bound) +// Traveling Salesman Problem (Little et al's Branch-and-Bound) // // Description: // It solves TSP exactly by branch-and-bound algorithm that @@ -8,7 +8,7 @@ // // In practice, it scales to networks with |V| <= 40. // -// +// // References: // J. D. C. Little, K. G. Murty, D. W. Sweeney, and C. Karel (1963): // An algorithm for traveling salesman problem. From 82e39c1e8369809bb84dc377be75cc899ac1f1de Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 08:18:50 +0900 Subject: [PATCH 020/141] Update README.md --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index 9717b8f..2682c37 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,3 @@ You can use them for any purpose without any warranty. author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) - -# List - -## Graph - -- [Maximum Flow (Ford-Fulkerson)](graph/maximum_flow_ford_fulkerson.cc) -- [Maximum Flow (Dinic)](graph/maximum_flow_dinic.cc) From 7db8dafc2d982b74b1cc0dafbb7ed3e64c3fe3a1 Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 11:38:21 +0900 Subject: [PATCH 021/141] test --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2682c37..4e7b8bf 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,8 @@ You can use them for any purpose without any warranty. author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) + + +# Test + +test From 41ae6207dae991fff677905c5f11b2d2f727bf30 Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 11:59:20 +0900 Subject: [PATCH 022/141] work --- README.md | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4e7b8bf..2d8d3d1 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,138 @@ You can use them for any purpose without any warranty. author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) -# Test +# List + +## Combinatorics + +[Next radix number](combinatorics/next_radix.cc) +[Unique hash for permutations](combinatorics/permutation_hash.cc) +[Permutation index](combinatorics/permutation_index.cc) +[Permutation index (general)](combinatorics/permutation_index_general.cc) + +data_structure/ZDD.cc +data_structure/cartesian_tree.cc +data_structure/cube.cc +data_structure/fenwick_tree.cc +data_structure/fenwick_tree_2d.cc +data_structure/minmax_heap.cc +data_structure/persistent_array.cc +data_structure/persistent_heap.cc +data_structure/persistent_rope.cc +data_structure/persistent_union_find.cc +data_structure/radix_heap.cc +data_structure/randomized_binary_search_tree.cc +data_structure/skew_heap.cc +data_structure/sparse_table.cc +data_structure/splay_tree.cc +data_structure/sqrt_array.cc +data_structure/union_find.cc +data_structure/union_find2.cc +data_structure/wavelet_matrix.cc +dynamic_programming/knapsack.cc +dynamic_programming/longest_increasing_subsequence.cc +dynamic_programming/minimum_coin_change.cc +dynamic_programming/rod_cutting.cc +geometry/!circle.cc +geometry/bk_tree.cc +geometry/convex_hull.cc +geometry/covered_range.cc +geometry/randomized_kd_tree.cc +geometry/rectangle_union.cc +geometry/rectilinear_mst.cc +geometry/vantage_point_tree.cc +graph/arborescence.cc +graph/arborescence2.cc +graph/articulation_points.cc +graph/betweenness_centrality.cc +graph/bipartite_matching.cc +graph/bipartite_matching_HK.cc +graph/cycle_enumeration.cc +graph/dominator_tree.cc +graph/dynamic_reachability_dag.cc +graph/euler_tour_tree.cc +graph/eulerian_path_undirected.cc +graph/gabow_edmonds.cc +graph/gomory_hu_tree.cc +graph/hamilton_cycle_ore.cc +graph/is_bipartite.cc +graph/is_chordal.cc +graph/is_claw_free.cc +graph/is_cograph.cc +graph/is_graphic.cc +graph/isomorphism.cc +graph/kariv_hakimi.cc +graph/kcore.cc +graph/kruskal.cc +graph/least_common_ancestor_doubling.cc +graph/least_common_ancestor_heavylight.cc +graph/least_common_ancestor_sparsetable.cc +graph/least_common_ancestor_tarjan.cc +graph/link_cut_tree.cc +graph/maximal_cliques.cc +graph/maximum_cut.cc +graph/maximum_flow_dinic.cc +graph/maximum_flow_ford_fulkerson.cc +graph/minimum_feedback_arc_set.cc +graph/minimum_mean_cycle.cc +graph/reachability.cc +graph/shortest_path_st.cc +graph/strongly_connected_component_gabow.cc +graph/strongly_connected_component_kosaraju.cc +graph/strongly_connected_component_tarjan.cc +graph/tomizawa_edmonds_karp.cc +graph/transitive_reduction_dag.cc +graph/traveling_salesman.cc +graph/tree_decomposition.cc +graph/tree_isomorphism.cc +machine_learning/bradley_terry.cc +math/KaratsubaMultiplication.cc +math/ODE_dormand_prince.cc +math/ODE_runge_kutta.cc +math/SimplexMethodLP.cc +math/assignment.cc +math/fast_fourier_transform.cc +math/fast_modulo_transform.cc +math/find_min_unimodal.cc +math/integrate.cc +math/integrate_DE.cc +math/linear_recursion.cc +math/matrix_bool.cc +math/matrix_double.cc +math/permanent.cc +math/polynomial_int.cc +math/quadratic_equation.cc +math/satisfiability.cc +math/satisfiability_hornsat.cc +math/satisfiability_twosat.cc +math/zero_one_IP_solver.cc +number_theory/carmichael_lambda.cc +number_theory/divisor_sigma.cc +number_theory/euler_phi.cc +number_theory/mobius_mu.cc +number_theory/modular_arithmetics.cc +number_theory/primes.cc +other/all_nearest_smaller_values.cc +other/calendar.cc +other/exact_cover.cc +other/knapsack_expcore.cc +other/sorting_network.cc +other/subset_sum.cc +other/unweighted_interval_scheduling.cc +other/weighted_interval_scheduling.cc +string/NFAtoDFA.cc +string/boyer_moore.cc +string/earley.cc +string/edit_distance_NFA.cc +string/factor_automaton.cc +string/infix_to_postfix.cc +string/knuth_morris_pratt.cc +string/palindromic_tree.cc +string/suffix_array.cc +string/suffix_tree.cc +string/sunday.cc + +## Misc +[Dictionary](_misc/dictionary.cc) +[Tick](_misc/tick.cc) -test From 46875ae93f689dc99e66d988ee4f25939de2919b Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 11:59:57 +0900 Subject: [PATCH 023/141] readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2d8d3d1..03906c3 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) ## Combinatorics -[Next radix number](combinatorics/next_radix.cc) -[Unique hash for permutations](combinatorics/permutation_hash.cc) -[Permutation index](combinatorics/permutation_index.cc) -[Permutation index (general)](combinatorics/permutation_index_general.cc) +- [Next radix number](combinatorics/next_radix.cc) +- [Unique hash for permutations](combinatorics/permutation_hash.cc) +- [Permutation index](combinatorics/permutation_index.cc) +- [Permutation index (general)](combinatorics/permutation_index_general.cc) data_structure/ZDD.cc data_structure/cartesian_tree.cc From d79ed9f1c1b9647ff10bf69d24120dccdff13fb3 Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 12:02:05 +0900 Subject: [PATCH 024/141] readme --- README.md | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 03906c3..aa2ce72 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) - [Permutation index](combinatorics/permutation_index.cc) - [Permutation index (general)](combinatorics/permutation_index_general.cc) + +## Data structure + data_structure/ZDD.cc data_structure/cartesian_tree.cc data_structure/cube.cc @@ -39,10 +42,20 @@ data_structure/sqrt_array.cc data_structure/union_find.cc data_structure/union_find2.cc data_structure/wavelet_matrix.cc + + +## Dynamic programming + +This category should be reorganized. + dynamic_programming/knapsack.cc dynamic_programming/longest_increasing_subsequence.cc dynamic_programming/minimum_coin_change.cc dynamic_programming/rod_cutting.cc + + +## Computational Geometry (2D) + geometry/!circle.cc geometry/bk_tree.cc geometry/convex_hull.cc @@ -51,6 +64,10 @@ geometry/randomized_kd_tree.cc geometry/rectangle_union.cc geometry/rectilinear_mst.cc geometry/vantage_point_tree.cc + + +## Graph Algorithms + graph/arborescence.cc graph/arborescence2.cc graph/articulation_points.cc @@ -95,7 +112,12 @@ graph/transitive_reduction_dag.cc graph/traveling_salesman.cc graph/tree_decomposition.cc graph/tree_isomorphism.cc -machine_learning/bradley_terry.cc + + +## Mathematics + +This category should be reorganized. + math/KaratsubaMultiplication.cc math/ODE_dormand_prince.cc math/ODE_runge_kutta.cc @@ -116,12 +138,21 @@ math/satisfiability.cc math/satisfiability_hornsat.cc math/satisfiability_twosat.cc math/zero_one_IP_solver.cc + + +## Number theory + number_theory/carmichael_lambda.cc number_theory/divisor_sigma.cc number_theory/euler_phi.cc number_theory/mobius_mu.cc number_theory/modular_arithmetics.cc number_theory/primes.cc + +## Other + +This category should be reorganized. + other/all_nearest_smaller_values.cc other/calendar.cc other/exact_cover.cc @@ -130,19 +161,9 @@ other/sorting_network.cc other/subset_sum.cc other/unweighted_interval_scheduling.cc other/weighted_interval_scheduling.cc -string/NFAtoDFA.cc -string/boyer_moore.cc -string/earley.cc -string/edit_distance_NFA.cc -string/factor_automaton.cc -string/infix_to_postfix.cc -string/knuth_morris_pratt.cc -string/palindromic_tree.cc -string/suffix_array.cc -string/suffix_tree.cc -string/sunday.cc + ## Misc -[Dictionary](_misc/dictionary.cc) -[Tick](_misc/tick.cc) +- [Dictionary](_misc/dictionary.cc) +- [Tick](_misc/tick.cc) From 5689ac54d84b65fbb6eca751a92390c400602296 Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 12:04:09 +0900 Subject: [PATCH 025/141] readme --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index aa2ce72..cec91a2 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ # C++ implementations of algorithms -These codes are my C++ implementations of algorithms, +These are my C++ implementations of algorithms, which are written for studying/understanding algorithms. -I publish these codes in *public domain.* -You can use them for any purpose without any warranty. -(but I strongly recommend you to "re-implement" the codes for your purpose.) +These codes are published in **public domain.** +You can use the codes for *any purpose without any warranty*. author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) From 21c33e00534270ac1103af6ce4811e8f31449e95 Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 12:09:22 +0900 Subject: [PATCH 026/141] readme --- README.md | 231 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 119 insertions(+), 112 deletions(-) diff --git a/README.md b/README.md index cec91a2..89bbcbc 100644 --- a/README.md +++ b/README.md @@ -22,144 +22,151 @@ author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) ## Data structure -data_structure/ZDD.cc -data_structure/cartesian_tree.cc -data_structure/cube.cc -data_structure/fenwick_tree.cc -data_structure/fenwick_tree_2d.cc -data_structure/minmax_heap.cc -data_structure/persistent_array.cc -data_structure/persistent_heap.cc -data_structure/persistent_rope.cc -data_structure/persistent_union_find.cc -data_structure/radix_heap.cc -data_structure/randomized_binary_search_tree.cc -data_structure/skew_heap.cc -data_structure/sparse_table.cc -data_structure/splay_tree.cc -data_structure/sqrt_array.cc -data_structure/union_find.cc -data_structure/union_find2.cc -data_structure/wavelet_matrix.cc +- [Zero suppressed decision diagram](data_structure/ZDD.cc) +- [Cartesian tree](data_structure/cartesian_tree.cc) +- [Fenwick tree](data_structure/fenwick_tree.cc) +- [2D Fenwick tree](data_structure/fenwick_tree_2d.cc) +- [Sparse Table](data_structure/sparse_table.cc) + +- [Randomized Binary Search Tree](data_structure/randomized_binary_search_tree.cc) +- [Splay Tree](data_structure/splay_tree.cc) + +- [Min-Max Heap](data_structure/minmax_heap.cc) +- [Radix Heap](data_structure/radix_heap.cc) +- [Skew Heap](data_structure/skew_heap.cc) + +- [Sqrt Array](data_structure/sqrt_array.cc) + +- [Union Find](data_structure/union_find.cc) +- [Traversable Union Find](data_structure/union_find2.cc) + +- [Wavelet Matrix](data_structure/wavelet_matrix.cc) + +- [Persistent array](data_structure/persistent_array.cc) +- [Persistent heap](data_structure/persistent_heap.cc) +- [Persistent rope](data_structure/persistent_rope.cc) +- [Persistent union find](data_structure/persistent_union_find.cc) + +- [Cube](data_structure/cube.cc) ## Dynamic programming This category should be reorganized. -dynamic_programming/knapsack.cc -dynamic_programming/longest_increasing_subsequence.cc -dynamic_programming/minimum_coin_change.cc -dynamic_programming/rod_cutting.cc +- dynamic_programming/knapsack.cc +- dynamic_programming/longest_increasing_subsequence.cc +- dynamic_programming/minimum_coin_change.cc +- dynamic_programming/rod_cutting.cc ## Computational Geometry (2D) -geometry/!circle.cc -geometry/bk_tree.cc -geometry/convex_hull.cc -geometry/covered_range.cc -geometry/randomized_kd_tree.cc -geometry/rectangle_union.cc -geometry/rectilinear_mst.cc -geometry/vantage_point_tree.cc +- geometry/!circle.cc +- geometry/bk_tree.cc +- geometry/convex_hull.cc +- geometry/covered_range.cc +- geometry/randomized_kd_tree.cc +- geometry/rectangle_union.cc +- geometry/rectilinear_mst.cc +- geometry/vantage_point_tree.cc ## Graph Algorithms -graph/arborescence.cc -graph/arborescence2.cc -graph/articulation_points.cc -graph/betweenness_centrality.cc -graph/bipartite_matching.cc -graph/bipartite_matching_HK.cc -graph/cycle_enumeration.cc -graph/dominator_tree.cc -graph/dynamic_reachability_dag.cc -graph/euler_tour_tree.cc -graph/eulerian_path_undirected.cc -graph/gabow_edmonds.cc -graph/gomory_hu_tree.cc -graph/hamilton_cycle_ore.cc -graph/is_bipartite.cc -graph/is_chordal.cc -graph/is_claw_free.cc -graph/is_cograph.cc -graph/is_graphic.cc -graph/isomorphism.cc -graph/kariv_hakimi.cc -graph/kcore.cc -graph/kruskal.cc -graph/least_common_ancestor_doubling.cc -graph/least_common_ancestor_heavylight.cc -graph/least_common_ancestor_sparsetable.cc -graph/least_common_ancestor_tarjan.cc -graph/link_cut_tree.cc -graph/maximal_cliques.cc -graph/maximum_cut.cc -graph/maximum_flow_dinic.cc -graph/maximum_flow_ford_fulkerson.cc -graph/minimum_feedback_arc_set.cc -graph/minimum_mean_cycle.cc -graph/reachability.cc -graph/shortest_path_st.cc -graph/strongly_connected_component_gabow.cc -graph/strongly_connected_component_kosaraju.cc -graph/strongly_connected_component_tarjan.cc -graph/tomizawa_edmonds_karp.cc -graph/transitive_reduction_dag.cc -graph/traveling_salesman.cc -graph/tree_decomposition.cc -graph/tree_isomorphism.cc - - +- graph/arborescence.cc +- graph/arborescence2.cc +- graph/articulation_points.cc +- graph/betweenness_centrality.cc +- graph/bipartite_matching.cc +- graph/bipartite_matching_HK.cc +- graph/cycle_enumeration.cc +- graph/dominator_tree.cc +- graph/dynamic_reachability_dag.cc +- graph/euler_tour_tree.cc +- graph/eulerian_path_undirected.cc +- graph/gabow_edmonds.cc +- graph/gomory_hu_tree.cc +- graph/hamilton_cycle_ore.cc +- graph/is_bipartite.cc +- graph/is_chordal.cc +- graph/is_claw_free.cc +- graph/is_cograph.cc +- graph/is_graphic.cc +- graph/isomorphism.cc +- graph/kariv_hakimi.cc +- graph/kcore.cc +- graph/kruskal.cc +- graph/least_common_ancestor_doubling.cc +- graph/least_common_ancestor_heavylight.cc +- graph/least_common_ancestor_sparsetable.cc +- graph/least_common_ancestor_tarjan.cc +- graph/link_cut_tree.cc +- graph/maximal_cliques.cc +- graph/maximum_cut.cc +- graph/maximum_flow_dinic.cc +- graph/maximum_flow_ford_fulkerson.cc +- graph/minimum_feedback_arc_set.cc +- graph/minimum_mean_cycle.cc +- graph/reachability.cc +- graph/shortest_path_st.cc +- graph/strongly_connected_component_gabow.cc +- graph/strongly_connected_component_kosaraju.cc +- graph/strongly_connected_component_tarjan.cc +- graph/tomizawa_edmonds_karp.cc +- graph/transitive_reduction_dag.cc +- graph/traveling_salesman.cc +- graph/tree_decomposition.cc +- graph/tree_isomorphism.cc + + ## Mathematics - + This category should be reorganized. -math/KaratsubaMultiplication.cc -math/ODE_dormand_prince.cc -math/ODE_runge_kutta.cc -math/SimplexMethodLP.cc -math/assignment.cc -math/fast_fourier_transform.cc -math/fast_modulo_transform.cc -math/find_min_unimodal.cc -math/integrate.cc -math/integrate_DE.cc -math/linear_recursion.cc -math/matrix_bool.cc -math/matrix_double.cc -math/permanent.cc -math/polynomial_int.cc -math/quadratic_equation.cc -math/satisfiability.cc -math/satisfiability_hornsat.cc -math/satisfiability_twosat.cc -math/zero_one_IP_solver.cc +- math/KaratsubaMultiplication.cc +- math/ODE_dormand_prince.cc +- math/ODE_runge_kutta.cc +- math/SimplexMethodLP.cc +- math/assignment.cc +- math/fast_fourier_transform.cc +- math/fast_modulo_transform.cc +- math/find_min_unimodal.cc +- math/integrate.cc +- math/integrate_DE.cc +- math/linear_recursion.cc +- math/matrix_bool.cc +- math/matrix_double.cc +- math/permanent.cc +- math/polynomial_int.cc +- math/quadratic_equation.cc +- math/satisfiability.cc +- math/satisfiability_hornsat.cc +- math/satisfiability_twosat.cc +- math/zero_one_IP_solver.cc ## Number theory -number_theory/carmichael_lambda.cc -number_theory/divisor_sigma.cc -number_theory/euler_phi.cc -number_theory/mobius_mu.cc -number_theory/modular_arithmetics.cc -number_theory/primes.cc +- number_theory/carmichael_lambda.cc +- number_theory/divisor_sigma.cc +- number_theory/euler_phi.cc +- number_theory/mobius_mu.cc +- number_theory/modular_arithmetics.cc +- number_theory/primes.cc ## Other This category should be reorganized. -other/all_nearest_smaller_values.cc -other/calendar.cc -other/exact_cover.cc -other/knapsack_expcore.cc -other/sorting_network.cc -other/subset_sum.cc -other/unweighted_interval_scheduling.cc -other/weighted_interval_scheduling.cc +- other/all_nearest_smaller_values.cc +- other/calendar.cc +- other/exact_cover.cc +- other/knapsack_expcore.cc +- other/sorting_network.cc +- other/subset_sum.cc +- other/unweighted_interval_scheduling.cc +- other/weighted_interval_scheduling.cc ## Misc From 7c8b0020ce1b6bc69d71c4f325a65894b373ac13 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 12:33:04 +0900 Subject: [PATCH 027/141] Coordinate Compression --- other/coordinate_compression.cc | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 other/coordinate_compression.cc diff --git a/other/coordinate_compression.cc b/other/coordinate_compression.cc new file mode 100644 index 0000000..09453be --- /dev/null +++ b/other/coordinate_compression.cc @@ -0,0 +1,40 @@ +// +// Coordinate Compression +// +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +struct coordinate_compression { + vector xs, ys; // O(n log n) + coordinate_compression(vector xs) : xs(xs), ys(xs) { + sort(all(ys)); + ys.erase(unique(all(ys)), ys.end()); + } + int index(T a) const { // O(log n) + auto it = lower_bound(all(ys), a); + if (it == ys.end() || *it != a) return -1; + return distance(ys.begin(), it); + } + int value(int k) const { return ys[k]; } // k in [0, ys.size()) + int size() const { return ys.size(); } +}; + + +int main() { + vector x = {3,1,4,1,5,9}; + coordinate_compression compressor(x); + for (int i = 0; i Date: Tue, 7 Jun 2016 12:34:24 +0900 Subject: [PATCH 028/141] Gregorian Calendar --- other/{calendar.cc => gregorian_calendar.cc} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename other/{calendar.cc => gregorian_calendar.cc} (95%) diff --git a/other/calendar.cc b/other/gregorian_calendar.cc similarity index 95% rename from other/calendar.cc rename to other/gregorian_calendar.cc index 27d24a4..66c389f 100644 --- a/other/calendar.cc +++ b/other/gregorian_calendar.cc @@ -2,7 +2,7 @@ // Calendar // // Description: -// A code for converting gregorian date <=> julian day number +// A code for converting gregorian date <=> julian day number. // #include From 05983be22ab0ad3c630add7717c0392d4e49966e Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 12:34:30 +0900 Subject: [PATCH 029/141] readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 89bbcbc..75d5e0d 100644 --- a/README.md +++ b/README.md @@ -159,8 +159,9 @@ This category should be reorganized. This category should be reorganized. +- [Coordinate Compression](other/coordinate_compression.cc) +- [Gregorian Calendar](other/gregorian_calendar.cc) - other/all_nearest_smaller_values.cc -- other/calendar.cc - other/exact_cover.cc - other/knapsack_expcore.cc - other/sorting_network.cc From 51918603f2d9984bc3ed903738613307d8a40c3c Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 12:36:38 +0900 Subject: [PATCH 030/141] Cube --- README.md | 9 +------- other/cube.cc | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 other/cube.cc diff --git a/README.md b/README.md index 75d5e0d..aaf4b46 100644 --- a/README.md +++ b/README.md @@ -27,28 +27,20 @@ author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) - [Fenwick tree](data_structure/fenwick_tree.cc) - [2D Fenwick tree](data_structure/fenwick_tree_2d.cc) - [Sparse Table](data_structure/sparse_table.cc) - - [Randomized Binary Search Tree](data_structure/randomized_binary_search_tree.cc) - [Splay Tree](data_structure/splay_tree.cc) - - [Min-Max Heap](data_structure/minmax_heap.cc) - [Radix Heap](data_structure/radix_heap.cc) - [Skew Heap](data_structure/skew_heap.cc) - - [Sqrt Array](data_structure/sqrt_array.cc) - - [Union Find](data_structure/union_find.cc) - [Traversable Union Find](data_structure/union_find2.cc) - - [Wavelet Matrix](data_structure/wavelet_matrix.cc) - - [Persistent array](data_structure/persistent_array.cc) - [Persistent heap](data_structure/persistent_heap.cc) - [Persistent rope](data_structure/persistent_rope.cc) - [Persistent union find](data_structure/persistent_union_find.cc) -- [Cube](data_structure/cube.cc) - ## Dynamic programming @@ -161,6 +153,7 @@ This category should be reorganized. - [Coordinate Compression](other/coordinate_compression.cc) - [Gregorian Calendar](other/gregorian_calendar.cc) +- [Cube](other/cube.cc) - other/all_nearest_smaller_values.cc - other/exact_cover.cc - other/knapsack_expcore.cc diff --git a/other/cube.cc b/other/cube.cc new file mode 100644 index 0000000..2224399 --- /dev/null +++ b/other/cube.cc @@ -0,0 +1,63 @@ +// +// Cube data structure +// +// Descrption: +// A data structure for cube has six faces on +// front, up, down, left, right, and bottom. +// It admits the following three rotations +// rotX: front -> up -> back -> down +// rotY: left -> up -> right -> down +// rotZ: left -> front -> right -> down +// +// Algorithm: +// Trivial. +// +// Verified: +// SPOJ 21526 +// +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +template +struct cube { + T F, U, D, L, R, B; + void rotX() { swap(D, B); swap(B, U); swap(U, F); } // FUBD -> DFUB + void rotY() { swap(D, R); swap(R, U); swap(U, L); } // LURD -> DLUR + void rotZ() { swap(B, R); swap(R, F); swap(F, L); } // LFRB -> BLFR +}; + +int main() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + cube c; + c.F = 0; c.U = 1; c.D = 2; c.L = 3; c.R = 4; c.B = 5; + char s[6][1024]; + for (int i = 0; i < 6; ++i) + scanf("%s", s[i]); + int q; scanf("%d", &q); + for (int i = 0; i < q; ++i) { + char t[1024]; + int k; + scanf("%s %d", t, &k); + k %= 4; + if (t[0] == 'X') { + while (k--) c.rotX(); + } else if (t[0] == 'Y') { + while (k--) c.rotY(); + } else { + while (k--) c.rotZ(); + } + } + printf("%s %s %s %s %s %s\n", + s[c.F], s[c.U], s[c.D], s[c.L], s[c.R], s[c.B]); + } +} From 25820857eef2104728d6e600e425cd4de89c6ff4 Mon Sep 17 00:00:00 2001 From: Takanori Maehara Date: Tue, 7 Jun 2016 12:37:41 +0900 Subject: [PATCH 031/141] readme --- README.md | 8 +++--- data_structure/cube.cc | 63 ------------------------------------------ 2 files changed, 4 insertions(+), 67 deletions(-) delete mode 100644 data_structure/cube.cc diff --git a/README.md b/README.md index aaf4b46..2152138 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,10 @@ author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) ## Data structure -- [Zero suppressed decision diagram](data_structure/ZDD.cc) -- [Cartesian tree](data_structure/cartesian_tree.cc) -- [Fenwick tree](data_structure/fenwick_tree.cc) -- [2D Fenwick tree](data_structure/fenwick_tree_2d.cc) +- [Zero Suppressed Decision Diagram (ZDD)](data_structure/ZDD.cc) +- [Cartesian Tree](data_structure/cartesian_tree.cc) +- [Fenwick Tree](data_structure/fenwick_tree.cc) +- [2D Fenwick Tree](data_structure/fenwick_tree_2d.cc) - [Sparse Table](data_structure/sparse_table.cc) - [Randomized Binary Search Tree](data_structure/randomized_binary_search_tree.cc) - [Splay Tree](data_structure/splay_tree.cc) diff --git a/data_structure/cube.cc b/data_structure/cube.cc deleted file mode 100644 index 2224399..0000000 --- a/data_structure/cube.cc +++ /dev/null @@ -1,63 +0,0 @@ -// -// Cube data structure -// -// Descrption: -// A data structure for cube has six faces on -// front, up, down, left, right, and bottom. -// It admits the following three rotations -// rotX: front -> up -> back -> down -// rotY: left -> up -> right -> down -// rotZ: left -> front -> right -> down -// -// Algorithm: -// Trivial. -// -// Verified: -// SPOJ 21526 -// -#include -#include -#include -#include -#include - -using namespace std; - -#define fst first -#define snd second -#define all(c) ((c).begin()), ((c).end()) - -template -struct cube { - T F, U, D, L, R, B; - void rotX() { swap(D, B); swap(B, U); swap(U, F); } // FUBD -> DFUB - void rotY() { swap(D, R); swap(R, U); swap(U, L); } // LURD -> DLUR - void rotZ() { swap(B, R); swap(R, F); swap(F, L); } // LFRB -> BLFR -}; - -int main() { - int ncase; scanf("%d", &ncase); - for (int icase = 0; icase < ncase; ++icase) { - cube c; - c.F = 0; c.U = 1; c.D = 2; c.L = 3; c.R = 4; c.B = 5; - char s[6][1024]; - for (int i = 0; i < 6; ++i) - scanf("%s", s[i]); - int q; scanf("%d", &q); - for (int i = 0; i < q; ++i) { - char t[1024]; - int k; - scanf("%s %d", t, &k); - k %= 4; - if (t[0] == 'X') { - while (k--) c.rotX(); - } else if (t[0] == 'Y') { - while (k--) c.rotY(); - } else { - while (k--) c.rotZ(); - } - } - printf("%s %s %s %s %s %s\n", - s[c.F], s[c.U], s[c.D], s[c.L], s[c.R], s[c.B]); - } -} From 94ac0a7909b8acc6882079abeb14af20ca4730ea Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 17:09:20 +0900 Subject: [PATCH 032/141] Poker Hands --- other/poker_hands.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 other/poker_hands.cc diff --git a/other/poker_hands.cc b/other/poker_hands.cc new file mode 100644 index 0000000..65525f0 --- /dev/null +++ b/other/poker_hands.cc @@ -0,0 +1,80 @@ +// +// Poker Hands +// +// Description: +// It determines the hand of the poker. +// +// Algorithm: +// Naive. +// +// Verified: +// UVA 10315 Poker Hands ( +// +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +struct card { + int rank, suit; + card(int rank, int suit) : rank(rank), suit(suit) { } + card(char s[]) { // s is, i.e., "7H" + for (rank = 0; s[0] != "_A23456789TJQK"[rank]; ++rank); + for (suit = 0; s[1] != "CDHS"[suit]; ++suit); + } +}; + +enum { + HIGHEST_CARD, ONE_PAIR, TWO_PAIR, THREE_OF_A_KIND, + STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH }; +pair> poker_hand(vector cs) { + vector code, freq(30); + for (card c: cs) freq[c.rank+13] = freq[c.rank] += 1; + for (int i = 14; i >= 2; --i) + if (freq[i]) code.push_back(i); + stable_sort(all(code), [&](int i, int j) { return freq[i] > freq[j]; }); + + bool straight = false, flush = true; + for (int i = 1, j; i <= 10; ++i) { // beginning of straight (10 == 'X') + for (j = 0; j < 5 && freq[i+j]; ++j); + if (j == 5) straight = true; + } + for (int i = 1; i < 5; ++i) + if (cs[0].suit != cs[i].suit) flush = false; + + if (straight && flush) return {STRAIGHT_FLUSH, code}; + if (freq[code[0]] == 4) return {FOUR_OF_A_KIND, code}; + if (freq[code[0]] == 3 && freq[code[1]] == 2) return {FULL_HOUSE, code}; + if (flush) return {FLUSH, code}; + if (straight) return {STRAIGHT, code}; + if (freq[code[0]] == 3) return {THREE_OF_A_KIND, code}; + if (freq[code[0]] == 2 && freq[code[1]] == 2) return {TWO_PAIR, code}; + if (freq[code[0]] == 2) return {ONE_PAIR, code}; + return {HIGHEST_CARD, code}; +}; + +int main() { + while (1) { + vector cs[2]; + pair> res[2]; + for (int k = 0; k < 2; ++k) { + for (int i = 0; i < 5; ++i) { + char s[120]; + if (scanf("%s", s) != 1) return 0;; + cs[k].push_back(card(s)); + } + res[k] = poker_hand(cs[k]); + } + if (res[0] < res[1]) printf("White wins.\n"); + else if (res[0] > res[1]) printf("Black wins.\n"); + else printf("Tie.\n"); + } +} From 0c427e0da35f7733325dc7d6fa3e361539ebc3f4 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 17:09:54 +0900 Subject: [PATCH 033/141] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2152138..871386c 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ This category should be reorganized. - [Coordinate Compression](other/coordinate_compression.cc) - [Gregorian Calendar](other/gregorian_calendar.cc) +- [Poker Hands](other/poker_hands.cc) - [Cube](other/cube.cc) - other/all_nearest_smaller_values.cc - other/exact_cover.cc From 7514d4b3fc6568572d55cc6eabf25764e6a4cede Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 17:37:23 +0900 Subject: [PATCH 034/141] Karatsuba Multiplication --- math/KaratsubaMultiplication.cc | 121 --------------------------- math/karatsuba_multiplication.cc | 138 +++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 121 deletions(-) delete mode 100644 math/KaratsubaMultiplication.cc create mode 100644 math/karatsuba_multiplication.cc diff --git a/math/KaratsubaMultiplication.cc b/math/KaratsubaMultiplication.cc deleted file mode 100644 index c9f3573..0000000 --- a/math/KaratsubaMultiplication.cc +++ /dev/null @@ -1,121 +0,0 @@ -// -// Karatsuba multiplication of polynomial -// -// Description: -// -// Given A(x) := a[0] + a[1] x + ... + a[an-1] x^{an-1} and -// B(x) := b[0] + b[1] x + ... + b[bn-1] x^{bn-1}, -// compute C(x) = A(x) B(x). -// -// In other words, compute the convolution of a and b: -// c[k] = (a * b)[k] := sum_{i+j == k} a[i] b[j] -// -// Algorithm: -// -// Karatsuba's divide-and-conquer. -// -// Let n := an/2. Divide A, B as follows: -// A(x) = Ah(x) x^n + Al(x), -// B(x) = Bh(x) x^n + Bl(x). -// Then C(x) = Ah(x) Bh(x) x^{2n} -// + (Ah(x) Bl(x) + Al(x) Bh(x)) x^n -// + Al(x) Bl(x). -// This formula requires 4 multiplications. -// -// To reduce the number of multiplications, -// we introduce the auxilialy term: -// D(x) = (Ah(x) + Al(x)) (Bh(x) + Bl(x)), -// then we have -// (Ah(x) Bl(x) + Al(x) Bh(x)) = D(x) - Ah(x) Al(x) - Bh(x) Bl(x). -// This formula requires only 3 multiplications. -// -// -// Complexity: -// -// O(n^log 3). -// In practive, it is faster than naive method for n >= 1000. -// -// -// Verified: -// SPOJ 31: Fast Multiplication -// (Remark: TLE for VFMUL) -// -// -// References: -// -// - A. Karatsuba and Y. Ofman (1962): -// Multiplication of Many-Digital Numbers by Automatic Computers, -// Proceedings of the USSR Academy of Sciences, vol.145, pp.293-294 - -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -#define REP(i,n) for(int i=0;i -double tick() { - static clock_t oldtick; - clock_t newtick = clock(); - double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; - oldtick = newtick; - return diff; -} - -const int N = 700; -LL a[N], b[N], c[2*N]; -int main() { - int an = N, bn = N-1, cn; - REP(i, an) a[i] = rand(); - REP(i, bn) b[i] = rand(); - - LL s; - tick(); - s = 0; - mul0(a, an, b, bn, c, cn); - REP(i, cn) s += c[i]; - cout << s << " " << tick() << endl; - - s = 0; - mul(a, an, b, bn, c, cn); - REP(i, cn) s += c[i]; - cout << s << " " << tick() << endl; -} diff --git a/math/karatsuba_multiplication.cc b/math/karatsuba_multiplication.cc new file mode 100644 index 0000000..25b9408 --- /dev/null +++ b/math/karatsuba_multiplication.cc @@ -0,0 +1,138 @@ +// Karatsuba multiplication +// +// Given A(x) := a[0] + a[1] x + ... + a[an-1] x^{an-1} and +// B(x) := b[0] + b[1] x + ... + b[bn-1] x^{bn-1}, +// Compute C(x) = A(x) B(x) +// +// i.e., c[k] = (a * b)[k] := sum_{i+j == k} a[i] b[j] (convolution) +// +// +// Complexity +// O(n^log 3), faster than naive method for n >= 1000 +// +// Verified +// SPOJ 31: Fast Multiplication +// (Remark: TLE for VFMUL) + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define REP(i,n) for(int i=0;i= 1000 +typedef long long LL; +void mul(LL a[], int an, LL b[], int bn, LL c[], int &cn) { + if (an < bn) { swap(an, bn); swap(a, b); } + cn = an + bn - 1; + memset(c, 0, sizeof(c[0])*cn); + if (bn <= 32) { + REP(i, an) REP(j, bn) c[i+j] += a[i]*b[j]; + return; + } + int m = (an+1)/2, n = min(m, bn), tn1, tn2, tn3; + LL *al = a, *ah = a+m, *bl = b, *bh = b+m; + LL tmp1[2*m], tmp2[2*m], tmp3[2*m]; + REP(i, m) tmp1[i] = al[i] + (i < an-m ? ah[i] : 0); + REP(i, n) tmp2[i] = bl[i] + (i < bn-n ? bh[i] : 0); + mul(tmp1, m, tmp2, n, tmp3, tn3); // = (al + ah)(bl + bh) + mul(al, m, bl, n, tmp1, tn1); // = al bl + mul(ah, an-m, bh, bn-n, tmp2, tn2); // = ah bh + + REP(i, tn1) { c[i] += tmp1[i]; c[i+m] -= tmp1[i]; } + REP(i, tn2) { c[i+2*m] += tmp2[i]; c[i+m] -= tmp2[i]; } + REP(i, tn3) c[i+m] += tmp3[i]; +} +void mul0(LL a[], int an, LL b[], int bn, LL c[], int &cn) { + cn = an + bn - 1; + memset(c, 0, sizeof(c[0])*cn); + REP(i, an) REP(j, bn) c[i+j] += a[i]*b[j]; +} + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +/* +const int N = 20000; +LL a[N], b[N], c[2*N]; +int main() { + for (int n = 2; n < 10000; n *= 2) { + printf("%d ", n); + int an = n, bn = n, cn; + REP(i, an) a[i] = rand(); + REP(i, bn) b[i] = rand(); + tick(); + mul0(a, an, b, bn, c, cn); + printf("%f ", tick()); + LL s; + s = 0; + REP(i, cn) s += c[i]; + + mul(a, an, b, bn, c, cn); + printf("%f ", tick()); + REP(i, cn) s -= c[i]; + printf("%d\n", s); + //cout << s << " " << tick() << endl; + } +} +*/ + +char s[300010]; +int d = 6; +LL B = 1000000; // = 10^d +void read(LL a[], int &an) { + scanf("%s", s); + int n = strlen(s); + reverse(s, s+n); + REP(i,2*d) s[n+i] = '0'; + + an = 0; + for (int i = 0; i < n; i += d) { + a[an] = 0; + for (int k = d-1; k >= 0; --k) + a[an] = a[an] * 10 + s[i+k] - '0'; + ++an; + } +} + +const int N = 300010; +LL a[N], b[N], c[2*N]; +int main() { + int T; scanf("%d", &T); + while (T--) { + memset(a, 0, sizeof(a)); + memset(b, 0, sizeof(b)); + memset(c, 0, sizeof(c)); + int an, bn, cn; + read(a, an); + read(b, bn); + mul(a, an, b, bn, c, cn); + REP(i, cn) { + if (c[i] >= B) { + if (i == cn-1) ++cn; + c[i+1] += c[i] / B; + c[i] %= B; + } + } + while (cn > 1 && c[cn-1] == 0) --cn; + printf("%d", c[--cn]); + while (cn > 0) printf("%0*d", d, c[--cn]); + printf("\n"); + } +} From c2fc2c3c415444eb2020a8ea7a10cb6fb570ec67 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 7 Jun 2016 17:37:58 +0900 Subject: [PATCH 035/141] Karatsuba Multiplication --- math/karatsuba_multiplication.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/math/karatsuba_multiplication.cc b/math/karatsuba_multiplication.cc index 25b9408..8de7972 100644 --- a/math/karatsuba_multiplication.cc +++ b/math/karatsuba_multiplication.cc @@ -8,11 +8,11 @@ // // // Complexity -// O(n^log 3), faster than naive method for n >= 1000 +// O(n^log 3), always faster than naive method // // Verified // SPOJ 31: Fast Multiplication -// (Remark: TLE for VFMUL) +// SPOJ 235: Very Fast Multiplication #include #include @@ -26,9 +26,6 @@ using namespace std; #define REP(i,n) for(int i=0;i= 1000 typedef long long LL; void mul(LL a[], int an, LL b[], int bn, LL c[], int &cn) { if (an < bn) { swap(an, bn); swap(a, b); } From 2a8157ebaa01e3f8b12b2091b838a733a79f4d66 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 8 Jun 2016 18:06:10 +0900 Subject: [PATCH 036/141] Maximum Flow (Dinic) --- graph/maximum_flow_dinic.cc | 42 +++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/graph/maximum_flow_dinic.cc b/graph/maximum_flow_dinic.cc index 8b637f3..f86d907 100644 --- a/graph/maximum_flow_dinic.cc +++ b/graph/maximum_flow_dinic.cc @@ -41,28 +41,29 @@ using namespace std; const long long INF = (1ll << 50); struct graph { - int n; + typedef long long flow_type; struct edge { int src, dst; - long long capacity, residue; + flow_type capacity, flow; size_t rev; }; + int n; vector> adj; graph(int n) : n(n), adj(n) { } - void add_edge(int src, int dst, long long capacity) { + void add_edge(int src, int dst, flow_type capacity) { adj[src].push_back({src, dst, capacity, 0, adj[dst].size()}); - adj[dst].push_back({dst, src, capacity, 0, adj[src].size()-1}); // bidirectional edge + adj[dst].push_back({dst, src, 0, 0, adj[src].size()-1}); } - long long max_flow(int s, int t) { + flow_type max_flow(int s, int t) { vector level(n), iter(n); - function levelize = [&]() { + function levelize = [&]() { // foward levelize level.assign(n, -1); level[s] = 0; queue Q; Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); if (u == t) break; for (auto &e: adj[u]) { - if (e.residue > 0 && level[e.dst] < 0) { + if (e.capacity > e.flow && level[e.dst] < 0) { Q.push(e.dst); level[e.dst] = level[u] + 1; } @@ -70,30 +71,31 @@ struct graph { } return level[t]; }; - function augment = [&](int u, long long cur) { + function augment = [&](int u, flow_type cur) { if (u == t) return cur; for (int &i = iter[u]; i < adj[u].size(); ++i) { - edge &e = adj[u][i]; - if (e.residue > 0 && level[u] < level[e.dst]) { - long long f = augment(e.dst, min(cur, e.residue)); + edge &e = adj[u][i], &r = adj[e.dst][e.rev]; + if (e.capacity > e.flow && level[u] < level[e.dst]) { + flow_type f = augment(e.dst, min(cur, e.capacity - e.flow)); if (f > 0) { - e.residue -= f; - adj[e.dst][e.rev].residue += f; + e.flow += f; + r.flow -= f; return f; } } } - return 0ll; + return flow_type(0); }; for (int u = 0; u < n; ++u) // initialize - for (auto &e: adj[u]) e.residue = e.capacity; - long long total = 0; + for (auto &e: adj[u]) e.flow = 0; + + flow_type flow = 0; while (levelize() >= 0) { fill(all(iter), 0); - for (long long f; (f = augment(s, INF)) > 0; ) - total += f; - } // level[u] == -1 ==> t-side - return total; + for (flow_type f; (f = augment(s, INF)) > 0; ) + flow += f; + } + return flow; } }; From 806635a1f503687a88f004cd6b91cc35649aedf2 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 8 Jun 2016 18:07:14 +0900 Subject: [PATCH 037/141] Maximum Flow (Ford-Fulkerson) --- graph/maximum_flow_ford_fulkerson.cc | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/graph/maximum_flow_ford_fulkerson.cc b/graph/maximum_flow_ford_fulkerson.cc index 7f62e1c..fe64636 100644 --- a/graph/maximum_flow_ford_fulkerson.cc +++ b/graph/maximum_flow_ford_fulkerson.cc @@ -34,44 +34,47 @@ using namespace std; const int INF = 1 << 30; struct graph { - int n; + typedef long long flow_type; struct edge { int src, dst; - int capacity, residue; + flow_type capacity, flow; size_t rev; }; + int n; vector> adj; graph(int n) : n(n), adj(n) { } - void add_edge(int src, int dst, int capacity) { + void add_edge(int src, int dst, flow_type capacity) { adj[src].push_back({src, dst, capacity, 0, adj[dst].size()}); adj[dst].push_back({dst, src, 0, 0, adj[src].size()-1}); } int max_flow(int s, int t) { vector visited(n); - function augment = [&](int u, int f = INF) { - if (u == t) return f; + function augment = [&](int u, flow_type cur) { + if (u == t) return cur; visited[u] = true; for (auto &e: adj[u]) { - if (!visited[e.dst] && e.residue > 0) { - int d = augment(e.dst, min(e.residue, f)); - if (d > 0) { - e.residue -= d; - adj[e.dst][e.rev].residue += d; - return d; + if (!visited[e.dst] && e.capacity > e.flow) { + flow_type f = augment(e.dst, min(e.capacity - e.flow, cur)); + if (f > 0) { + e.flow += f; + adj[e.dst][e.rev].flow -= f; + return f; } } } - return 0; + return flow_type(0); }; for (int u = 0; u < n; ++u) - for (auto &e: adj[u]) e.residue = e.capacity; + for (auto &e: adj[u]) e.flow = 0; - int total = 0; - for (int f = 1; f; ) { + flow_type flow = 0; + while (1) { fill(all(visited), false); - total += (f = augment(s, INF)); - } // { u : visited[u] == true } is s-side - return total; + flow_type f = augment(s, INF); + if (f == 0) break; + flow += f; + } + return flow; } }; From a7b2a333befd8148e7c0d6d411591920e8836872 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 8 Jun 2016 18:09:15 +0900 Subject: [PATCH 038/141] Maximum Flow (Edmonds-Karp) --- graph/maximum_flow_edmonds_karp.cc | 92 ++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 graph/maximum_flow_edmonds_karp.cc diff --git a/graph/maximum_flow_edmonds_karp.cc b/graph/maximum_flow_edmonds_karp.cc new file mode 100644 index 0000000..450e78a --- /dev/null +++ b/graph/maximum_flow_edmonds_karp.cc @@ -0,0 +1,92 @@ +// +// Maximum Flow (Edmonds-Karp) +// +// Description: +// Given a directed network G = (V, E) with edge capacity c: E->R. +// The algorithm finds a maximum flow. +// +// Algorithm: +// Edmonds-Karp shortest augmenting path algorithm. +// +// Complexity: +// O(n m^2) +// +// Verified: +// AOJ GRL_6_A: Maximum Flow +// +// Reference: +// B. H. Korte and J. Vygen (2008): +// Combinatorial Optimization: Theory and Algorithms. +// Springer Berlin Heidelberg. +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +const long long INF = (1ll << 50); +struct graph { + typedef long long flow_type; + struct edge { + int src, dst; + flow_type capacity, flow; + size_t rev; + }; + int n; + vector> adj; + graph(int n) : n(n), adj(n) { } + void add_edge(int src, int dst, flow_type capacity) { + adj[src].push_back({src, dst, capacity, 0, adj[dst].size()}); + adj[dst].push_back({dst, src, 0, 0, adj[src].size()-1}); + } + int max_flow(int s, int t) { + vector visited(n); + function augment = [&](int u, flow_type cur) { + if (u == t) return cur; + visited[u] = true; + for (auto &e: adj[u]) { + if (!visited[e.dst] && e.capacity > e.flow) { + flow_type f = augment(e.dst, min(e.capacity - e.flow, cur)); + if (f > 0) { + e.flow += f; + adj[e.dst][e.rev].flow -= f; + return f; + } + } + } + return flow_type(0); + }; + for (int u = 0; u < n; ++u) + for (auto &e: adj[u]) e.flow = 0; + + flow_type flow = 0; + while (1) { + fill(all(visited), false); + flow_type f = augment(s, INF); + if (f == 0) break; + flow += f; + } + return flow; + } +}; + +int main() { + for (int n, m; scanf("%d %d", &n, &m) == 2; ) { + graph g(n); + for (int i = 0; i < m; ++i) { + int u, v, w; + scanf("%d %d %d", &u, &v, &w); + g.add_edge(u, v, w); + } + printf("%d\n", g.max_flow(0, n-1)); + } +} From a6c483a18861fbeda6466fa6d0ef93a0452b847f Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 8 Jun 2016 18:10:13 +0900 Subject: [PATCH 039/141] Maximum Flow (Goldberg-Tarjan) --- graph/maximum_flow_goldberg_tarjan.cc | 121 ++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 graph/maximum_flow_goldberg_tarjan.cc diff --git a/graph/maximum_flow_goldberg_tarjan.cc b/graph/maximum_flow_goldberg_tarjan.cc new file mode 100644 index 0000000..1154d04 --- /dev/null +++ b/graph/maximum_flow_goldberg_tarjan.cc @@ -0,0 +1,121 @@ +// +// Maximum Flow (Goldberg-Tarjan, aka. Push-Relabel, Preflow-Push) +// +// Description: +// Given a directed network G = (V, E) with edge capacity c: E->R. +// The algorithm finds a maximum flow. +// +// Algorithm: +// Goldberg-Tarjan's push-relabel algorithm with gap-heuristics. +// +// Complexity: +// O(n^3) +// +// Verified: +// SPOJ FASTFLOW +// +// Reference: +// B. H. Korte and Jens Vygen (2008): +// Combinatorial Optimization: Theory and Algorithms. +// Springer Berlin Heidelberg. +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +const long long INF = (1ll << 50); +struct graph { + typedef long long flow_type; + struct edge { + int src, dst; + flow_type capacity, flow; + size_t rev; + }; + int n; + vector> adj; + graph(int n) : n(n), adj(n) { } + + void add_edge(int src, int dst, int capacity) { + adj[src].push_back({src, dst, capacity, 0, adj[dst].size()}); + adj[dst].push_back({dst, src, 0, 0, adj[src].size() - 1}); + } + + flow_type max_flow(int s, int t) { + vector excess(n); + vector dist(n), active(n), count(2*n); + queue Q; + auto enqueue = [&](int v) { + if (!active[v] && excess[v] > 0) { active[v] = true; Q.push(v); } + }; + auto push = [&](edge &e) { + flow_type f = min(excess[e.src], e.capacity - e.flow); + if (dist[e.src] <= dist[e.dst] || f == 0) return; + e.flow += f; + adj[e.dst][e.rev].flow -= f; + excess[e.dst] += f; + excess[e.src] -= f; + enqueue(e.dst); + }; + + dist[s] = n; active[s] = active[t] = true; + count[0] = n-1; count[n] = 1; + for (int u = 0; u < n; ++u) + for (auto &e: adj[u]) e.flow = 0; + for (auto &e: adj[s]) { + excess[s] += e.capacity; + push(e); + } + while (!Q.empty()) { + int u = Q.front(); Q.pop(); + active[u] = false; + + for (auto &e: adj[u]) push(e); + if (excess[u] > 0) { + if (count[dist[u]] == 1) { + int k = dist[u]; // Gap Heuristics + for (int v = 0; v < n; v++) { + if (dist[v] < k) continue; + count[dist[v]]--; + dist[v] = max(dist[v], n+1); + count[dist[v]]++; + enqueue(v); + } + } else { + count[dist[u]]--; // Relabel + dist[u] = 2*n; + for (auto &e: adj[u]) + if (e.capacity > e.flow) + dist[u] = min(dist[u], dist[e.dst] + 1); + count[dist[u]]++; + enqueue(u); + } + } + } + + flow_type flow = 0; + for (auto e: adj[s]) flow += e.flow; + return flow; + } +}; + +int main() { + for (int n, m; scanf("%d %d", &n, &m) == 2; ) { + graph g(n); + for (int i = 0; i < m; ++i) { + int u, v, w; + scanf("%d %d %d", &u, &v, &w); + g.add_edge(u, v, w); + } + printf("%d\n", g.max_flow(0, n-1)); + } +} From 48ea468a773e23ba85735e0bdd8f6b7ddb64ba4b Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 8 Jun 2016 18:45:09 +0900 Subject: [PATCH 040/141] Minimum Cost Maximum Flow (Tomizawa, Edmonds-Karp) --- ...cost_maximum_flow_tomizawa_edmonds_karp.cc | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc diff --git a/graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc b/graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc new file mode 100644 index 0000000..e5a1fcf --- /dev/null +++ b/graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc @@ -0,0 +1,169 @@ +// +// Minimum Cost Maximum Flow (Tomizawa, Edmonds-Karp) +// +// Description: +// Given a directed graph G = (V,E) with nonnegative capacity c and cost w. +// The algorithm find a maximum s-t flow of G with minimum cost. +// +// Algorithm: +// Tomizawa (1971), and Edmonds and Karp (1972)'s +// successive shortest path algorithm, +// which is also known as the primal-dual method. +// +// Complexity: +// O(F m log n), where F is the amount of maximum flow. +// +// References: +// N. Tomizawa (1971): +// On some techniques useful for solution of transportation network problems. +// Networks, vol. pp. 173-194. +// +// J. Edmonds and R.M. Karp (1972): +// Theoretical improvements in algorithmic efficiency for network flow problems. +// Journal of ACM, vol. 19, pp. 248-264. +// +// Historical Note: +// The successive shortest path type algorithm was developped +// independently by Jewell (1958), Iri (1960), and Busacker and Gowen (1961). +// Later, Tomizawa (1971), and Edmonds and Karp (1972) independently +// suggested to use vertex potential in shortest path algorithm. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +const long long INF = 99999999; +struct graph { + typedef int flow_type; + typedef int cost_type; + struct edge { + int src, dst; + flow_type capacity, flow; + cost_type cost; + size_t rev; + }; + vector edges; + void add_edge(int src, int dst, flow_type cap, cost_type cost) { + adj[src].push_back({src, dst, cap, 0, cost, adj[dst].size()}); + adj[dst].push_back({dst, src, 0, 0, -cost, adj[src].size()-1}); + } + int n; + vector> adj; + graph(int n) : n(n), adj(n) { } + + pair min_cost_max_flow(int s, int t) { + flow_type flow = 0; + cost_type cost = 0; + + for (int u = 0; u < n; ++u) // initialize + for (auto &e: adj[u]) e.flow = 0; + + vector p(n, 0); + + auto rcost = [&](edge e) { return e.cost + p[e.src] - p[e.dst]; }; + for (int iter = 0; ; ++iter) { + vector prev(n, -1); prev[s] = 0; + vector dist(n, INF); dist[s] = 0; + if (iter == 0) { // use Bellman-Ford to remove negative cost edges + vector count(n); count[s] = 1; + queue que; + for (que.push(s); !que.empty(); ) { + int u = que.front(); que.pop(); + count[u] = -count[u]; + for (auto &e: adj[u]) { + if (e.capacity > e.flow && dist[e.dst] > dist[e.src] + rcost(e)) { + dist[e.dst] = dist[e.src] + rcost(e); + prev[e.dst] = e.rev; + if (count[e.dst] <= 0) { + count[e.dst] = -count[e.dst] + 1; + que.push(e.dst); + } + } + } + } + } else { // use Dijkstra + typedef pair node; + priority_queue, greater> que; + que.push({0, s}); + while (!que.empty()) { + node a = que.top(); que.pop(); + if (a.snd == t) break; + if (dist[a.snd] > a.fst) continue; + for (auto e: adj[a.snd]) { + if (e.capacity > e.flow && dist[e.dst] > a.fst + rcost(e)) { + dist[e.dst] = dist[e.src] + rcost(e); + prev[e.dst] = e.rev; + que.push({dist[e.dst], e.dst}); + } + } + } + } + if (prev[t] == -1) break; + + for (int u = 0; u < n; ++u) + if (dist[u] < dist[t]) p[u] += dist[u] - dist[t]; + + function augment = [&](int u, flow_type cur) { + if (u == s) return cur; + edge &r = adj[u][prev[u]], &e = adj[r.dst][r.rev]; + flow_type f = augment(e.src, min(e.capacity - e.flow, cur)); + e.flow += f; r.flow -= f; + return f; + }; + flow_type f = augment(t, INF); + flow += f; + cost += f * (p[t] - p[s]); + } + return {flow, cost}; + } +}; + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +int main() { + for (int seed = 0; seed < 100; ++seed) { + cout << "--------------------" << endl; + + cout << "seed = " << seed << endl; + srand(seed); + + int n = 500; + graph g(n); + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + if (rand() % 2) g.add_edge(i, j, 1+rand()%100, 1+rand()%100); + if (rand() % 2) g.add_edge(j, i, 1+rand()%100, 1+rand()%100); + } + } + int s = 0, t = n-1; + tick(); + auto a = g.min_cost_max_flow(s, t); + cout << a.fst << " " << a.snd << " " << tick() << endl; +} +} From f63d3b56d076a3376f6e9330110a52127e22302b Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 8 Jun 2016 18:46:04 +0900 Subject: [PATCH 041/141] Create tomizawa_edmonds_karp.cc --- graph/tomizawa_edmonds_karp.cc | 176 --------------------------------- 1 file changed, 176 deletions(-) diff --git a/graph/tomizawa_edmonds_karp.cc b/graph/tomizawa_edmonds_karp.cc index 8635cb9..8b13789 100644 --- a/graph/tomizawa_edmonds_karp.cc +++ b/graph/tomizawa_edmonds_karp.cc @@ -1,177 +1 @@ -// -// Minimum Cost Flow (Tomizawa, Edmonds-Karp) -// -// -// Description: -// Given a directed graph G = (V,E) with nonnegative capacity c and cost w. -// The algorithm find a maximum s-t flow of G with minimum cost. -// -// -// Algorithm: -// Tomizawa (1971), and Edmonds and Karp (1972)'s -// successive shortest path algorithm, -// which is also known as the primal-dual method. -// -// -// Complexity: -// O(F m log n), where F is the amount of maximum flow. -// -// -// References: -// N. Tomizawa (1971): -// On some techniques useful for solution of transportation network problems. -// Networks, vol. pp. 173-194. -// -// J. Edmonds and R.M. Karp (1972): -// Theoretical improvements in algorithmic efficiency for network flow problems. -// Journal of ACM, vol. 19, pp. 248-264. -// -// -// Historical Note: -// The successive shortest path type algorithm was developped -// independently by Jewell (1958), Iri (1960), and Busacker and Gowen (1961). -// Later, Tomizawa (1971), and Edmonds and Karp (1972) independently -// suggested to use vertex potential in shortest path algorithm. -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - - -typedef long long cost_type; -typedef long long flow_type; -const flow_type INF = 99999999; -struct min_cost_max_flow { - struct edge { - int src, dst; - flow_type residue; - cost_type cost; - int rev; - }; - vector edges; - void add_edge(int src, int dst, flow_type cap, cost_type cost) { - edges.push_back({src, dst, cap, cost}); - } - int n; - vector> adj; - void make_graph(int n_ = 0) { - n = n_; - for (auto e: edges) - n = max(n, max(e.src, e.dst)+1); - adj.resize(n); - for (auto e: edges) { - edge r = {e.dst, e.src, 0, -e.cost}; - adj[e.src].push_back(e); - adj[r.src].push_back(r); - adj[e.src].back().rev = adj[r.src].size()-1; - adj[r.src].back().rev = adj[e.src].size()-1; - } - } - vector potential; - cost_type rcost(const edge &e) { - return e.cost + potential[e.src] - potential[e.dst]; - } - void bellman_ford(int s) { - for (int k = 0; k < n; ++k) - for (int u = 0; u < n; ++u) - for (auto e: adj[u]) - if (e.residue > 0 && rcost(e) < 0) - potential[e.dst] += rcost(e); - } - vector dist; - vector back; - flow_type dijkstra(int s, int t) { - fill(dist.begin(), dist.end(), INF); - dist[s] = 0; - typedef pair node; - priority_queue, greater> Q; - Q.push({0, s}); - while (!Q.empty()) { - auto p = Q.top(); Q.pop(); - if (dist[p.second] < p.first) continue; - if (p.second == t) break; - for (edge &e: adj[p.second]) { - if (e.residue <= 0) continue; - if (dist[e.dst] > dist[e.src] + rcost(e)) { - dist[e.dst] = dist[e.src] + rcost(e); - back[e.dst] = &e; - Q.push({dist[e.dst], e.dst}); - } - } - } - return dist[t]; - } - pair solve(int s, int t) { - flow_type flow = 0; - cost_type cost = 0; - - potential.assign(n, 0); - dist.resize(n); - back.resize(n); - //bellman_ford(s); // remove negative costs - - while (dijkstra(s, t) < INF) { - for (int u = 0; u < n; ++u) - if (dist[u] < dist[t]) - potential[u] += dist[u] - dist[t]; - - flow_type f = INF; - for (int u = t; u != s; u = back[u]->src) - f = min(f, back[u]->residue); - for (int u = t; u != s; u = back[u]->src) { - back[u]->residue -= f; - adj[back[u]->dst][back[u]->rev].residue += f; - } - flow += f; - cost += f * (potential[t] - potential[s]); - } - return {flow, cost}; - } -}; - - -// === tick a time === -#include -double tick() { - static clock_t oldtick; - clock_t newtick = clock(); - double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; - oldtick = newtick; - return diff; -} - -int main() { - for (int seed = 0; seed < 100; ++seed) { - cout << "--------------------" << endl; - - cout << "seed = " << seed << endl; - srand(seed); - - int n = 500; - min_cost_max_flow mcmf; - - for (int i = 0; i < n; ++i) { - for (int j = 0; j < i; ++j) { - if (rand() % 2) mcmf.add_edge(i, j, 1+rand()%100, 1+rand()%100); - if (rand() % 2) mcmf.add_edge(j, i, 1+rand()%100, 1+rand()%100); - } - } - mcmf.make_graph(n); - int s = 0, t = n-1; - tick(); - auto a = mcmf.solve(s, t); - cout << a.first << " " << a.second << " " << tick() << endl; - } -} From 4c6ae0ad807d9be5e8aec9b73e4c9a87e410e460 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 8 Jun 2016 18:46:12 +0900 Subject: [PATCH 042/141] Delete tomizawa_edmonds_karp.cc --- graph/tomizawa_edmonds_karp.cc | 1 - 1 file changed, 1 deletion(-) delete mode 100644 graph/tomizawa_edmonds_karp.cc diff --git a/graph/tomizawa_edmonds_karp.cc b/graph/tomizawa_edmonds_karp.cc deleted file mode 100644 index 8b13789..0000000 --- a/graph/tomizawa_edmonds_karp.cc +++ /dev/null @@ -1 +0,0 @@ - From 175f71b9969093c026f05dd6176121cb85a7684a Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 9 Jun 2016 07:57:04 +0900 Subject: [PATCH 043/141] Minimum Mean Cycle (Karp) --- graph/minimum_mean_cycle.cc | 84 +++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/graph/minimum_mean_cycle.cc b/graph/minimum_mean_cycle.cc index 0a2ccab..7d43926 100644 --- a/graph/minimum_mean_cycle.cc +++ b/graph/minimum_mean_cycle.cc @@ -46,51 +46,71 @@ using namespace std; #define snd second #define all(c) ((c).begin()), ((c).end()) -typedef int weight_type; -const weight_type INF = 99999999; -struct edge { - int src, dst; - weight_type weight; -}; struct graph { + typedef int weight_type; + const weight_type INF = 99999999; + struct edge { + int src, dst; + weight_type weight; + }; int n; vector> adj; - graph(int n = 0) : n(n) { } + graph(int n) : n(n), adj(n) { } void add_edge(int src, int dst, weight_type weight) { - // must be directed - // negative edges are allowed - n = max(n, max(src, dst)+1); - adj.resize(n); adj[src].push_back({src, dst, weight}); } - pair min_mean_cycle() { - vector> dist(n+1, vector(n, INF)); - dist[0][0] = 0; - for (int k = 0; k < n; ++k) - for (int u = 0; u < n; ++u) - for (auto e: adj[u]) - dist[k+1][e.dst] = min(dist[k+1][e.dst], dist[k][e.src] + e.weight); - weight_type num = 1; - int den = 0; - for (int k = 0; k < n; ++k) - for (int u = 0; u < n; ++u) - if (dist[k][u] < INF) - if (num * (n-k) > (dist[n][u]-dist[k][u]) * den) { - num = (dist[n][u] - dist[k][u]); - den = n-k; + typedef pair fraction; + fraction min_mean_cycle() { + vector> dist(n+1, vector(n)); + vector> prev(n+1, vector(n, -1)); + fill(all(prev[0]), 0); + + for (int k = 0; k < n; ++k) { + for (int u = 0; u < n; ++u) { + if (prev[k][u] < 0) continue; + for (auto e: adj[u]) { + if (prev[k+1][e.dst] < 0 || + dist[k+1][e.dst] > dist[k][e.src] + e.weight) { + dist[k+1][e.dst] = dist[k][e.src] + e.weight; + prev[k+1][e.dst] = e.src; } - return {num, den}; // ratio = num/den + } + } + } + int v = -1; + fraction opt = {1, 0}; // +infty + for (int u = 0; u < n; ++u) { + fraction f = {-1, 0}; // -infty + for (int k = n-1; k >= 0; --k) { + if (prev[k][u] < 0) continue; + fraction g = {dist[n][u] - dist[k][u], n - k}; + if (f.fst * g.snd < f.snd * g.fst) f = g; + } + if (opt.fst * f.snd > f.fst * opt.snd) { opt = f; v = u; } + } + if (v >= 0) { // found a loop + vector p; // path + for (int k = n; p.size() < 2 || p[0] != p.back(); v = prev[k--][v]) + p.push_back(v); + reverse(all(p)); + } + return opt; } }; int main() { - graph solver; - int n = 10; - for (int i = 0; i < n; ++i) - for (int j = 0; j < n; ++j) - solver.add_edge(i, j, (rand() % (2*n)) - n); + srand( 4 ); + int n = 4; + graph solver(n); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (i == j) continue; + int c = (rand() % (2*n)) - n; + solver.add_edge(i, j, c); + } + } auto p = solver.min_mean_cycle(); cout << p.fst << "/" << p.snd << endl; From f7ec97a9c00f9617d513f24cf4d5ec1ea6b8f3a3 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 9 Jun 2016 08:12:19 +0900 Subject: [PATCH 044/141] Minimum Cost Maximum Flow (Goldberg-Tarjan's minimum mean cycle canceling) --- ..._cost_maximum_flow_goldberg_tarjan_mmcc.cc | 331 ++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 graph/minimum_cost_maximum_flow_goldberg_tarjan_mmcc.cc diff --git a/graph/minimum_cost_maximum_flow_goldberg_tarjan_mmcc.cc b/graph/minimum_cost_maximum_flow_goldberg_tarjan_mmcc.cc new file mode 100644 index 0000000..248d579 --- /dev/null +++ b/graph/minimum_cost_maximum_flow_goldberg_tarjan_mmcc.cc @@ -0,0 +1,331 @@ +// +// Minimum Cost Maximum Flow (Goldberg-Tarjan's minimum mean cycle canceling) +// +// Description: +// Given a directed graph G = (V,E) with nonnegative capacity c and cost w. +// The algorithm find a maximum s-t flow of G with minimum cost. +// +// Algorithm: +// Goldberg-Tarjan (Tomizawa (1971)'s algorithm. +// It first finds a feasible (i.e., maximum) flow. Then it successively +// finds negative cycles, and cancels them. +// By finding minimum mean cycle, it finishes in strongly polynomial time. +// +// Complexity: +// O(n^2 m^2 log(nC), where C is the maximum capacity. +// Practically, this is much slower than other algorithms. +// +// References: +// A. Goldberg and R. E. Tarjan (1989): +// Finding minimum-cost circulations by canceling negative cycles. +// Journal of the ACM, vol. 36, no. 4, pp. 873--886. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +#define DEBUG 0 + +const long long INF = 99999999; +namespace NegativeCycleCanceling { +struct graph { + typedef int flow_type; + typedef int cost_type; + struct edge { + int src, dst; + flow_type capacity, flow; + cost_type cost; + size_t rev; + }; + vector edges; + void add_edge(int src, int dst, flow_type cap, cost_type cost) { + adj[src].push_back({src, dst, cap, 0, cost, adj[dst].size()}); + adj[dst].push_back({dst, src, 0, 0, -cost, adj[src].size()-1}); + } + int n; + vector> adj; + graph(int n) : n(n), adj(n) { } + + flow_type max_flow(int s, int t) { + vector level(n), iter(n); + function levelize = [&]() { // foward levelize + level.assign(n, -1); level[s] = 0; + queue Q; Q.push(s); + while (!Q.empty()) { + int u = Q.front(); Q.pop(); + if (u == t) break; + for (auto &e: adj[u]) { + if (e.capacity > e.flow && level[e.dst] < 0) { + Q.push(e.dst); + level[e.dst] = level[u] + 1; + } + } + } + return level[t]; + }; + function augment = [&](int u, flow_type cur) { + if (u == t) return cur; + for (int &i = iter[u]; i < adj[u].size(); ++i) { + edge &e = adj[u][i], &r = adj[e.dst][e.rev]; + if (e.capacity > e.flow && level[u] < level[e.dst]) { + flow_type f = augment(e.dst, min(cur, e.capacity - e.flow)); + if (f > 0) { + e.flow += f; + r.flow -= f; + return f; + } + } + } + return flow_type(0); + }; + for (int u = 0; u < n; ++u) // initialize + for (auto &e: adj[u]) e.flow = 0; + + flow_type flow = 0; + while (levelize() >= 0) { + fill(all(iter), 0); + for (flow_type f; (f = augment(s, INF)) > 0; ) + flow += f; + } + return flow; + } + + void disp() { + if (!DEBUG) return; + cout << "--------" << endl; + for (int u = 0; u < n; ++u) + for (auto e: adj[u]) { + cout << e.src << " " << e.dst << " " << e.capacity << " " << e.flow << " " << e.cost << endl; + } + cost_type cost = 0; + for (int u = 0; u < n; ++u) + for (auto &e: adj[u]) + if (e.flow > 0) cost += e.flow * e.cost; + cout << "cost = " << cost << endl; + } + + bool minimum_mean_cycle_cancel() { + vector> dist(n+1, vector(n)); + vector> prev(n+1, vector(n, -1)); + fill(all(prev[0]), 0); + + for (int k = 0; k < n; ++k) { + for (int u = 0; u < n; ++u) { + if (prev[k][u] < 0) continue; + for (auto e: adj[u]) { + if (e.capacity <= e.flow) continue; + if (prev[k+1][e.dst] < 0 || dist[k+1][e.dst] > dist[k][u] + e.cost) { + dist[k+1][e.dst] = dist[k][u] + e.cost; + prev[k+1][e.dst] = e.rev; + } + } + } + } + flow_type num = INF; + int v, den = 1; + for (int u = 0; u < n; ++u) { + flow_type num_u = -INF; + int den_u = 0; + for (int k = 0; k < n; ++k) { + if (prev[k][u] < 0) continue; + if (num_u * (n-k) < (dist[n][u]-dist[k][u]) * den_u) { + num_u = (dist[n][u] - dist[k][u]); den_u = n-k; + } + } + if (den_u > 0 && num * den_u > num_u * den) { + num = num_u; den = den_u; v = u; + } + } + if (num >= 0) return false; + vector back(n, -1); + for (int k = n; back[v] < 0; --k) { + back[v] = prev[k][v]; + edge &r = adj[v][back[v]]; + v = r.dst; + } + function augment = [&](int u, flow_type cur) { + if (cur < INF && u == v) return cur; + edge &r = adj[u][back[u]], &e = adj[r.dst][r.rev]; + flow_type f = augment(r.dst, min(e.capacity - e.flow, cur)); + e.flow += f; + r.flow -= f; + return f; + }; + augment(v, INF); + return true; + } + pair min_cost_max_flow(int s, int t) { + flow_type flow = max_flow(s, t); + while (minimum_mean_cycle_cancel()); + cost_type cost = 0; + for (int u = 0; u < n; ++u) + for (auto &e: adj[u]) + if (e.flow > 0) cost += e.flow * e.cost; + return {flow, cost}; + } +}; +} + +// for comparison +namespace Tomizawa_Edmonds_Karp { +struct graph { + typedef int flow_type; + typedef int cost_type; + struct edge { + int src, dst; + flow_type capacity, flow; + cost_type cost; + size_t rev; + }; + vector edges; + void add_edge(int src, int dst, flow_type cap, cost_type cost) { + adj[src].push_back({src, dst, cap, 0, cost, adj[dst].size()}); + adj[dst].push_back({dst, src, 0, 0, -cost, adj[src].size()-1}); + } + int n; + vector> adj; + graph(int n) : n(n), adj(n) { } + + pair min_cost_max_flow(int s, int t) { + flow_type flow = 0; + cost_type cost = 0; + + for (int u = 0; u < n; ++u) // initialize + for (auto &e: adj[u]) e.flow = 0; + + vector p(n, 0); + + auto rcost = [&](edge e) { return e.cost + p[e.src] - p[e.dst]; }; + for (int iter = 0; ; ++iter) { + vector prev(n, -1); prev[s] = 0; + vector dist(n, INF); dist[s] = 0; + if (iter == 0) { // use Bellman-Ford to remove negative cost edges + vector count(n); count[s] = 1; + queue que; + for (que.push(s); !que.empty(); ) { + int u = que.front(); que.pop(); + count[u] = -count[u]; + for (auto &e: adj[u]) { + if (e.capacity > e.flow && dist[e.dst] > dist[e.src] + rcost(e)) { + dist[e.dst] = dist[e.src] + rcost(e); + prev[e.dst] = e.rev; + if (count[e.dst] <= 0) { + count[e.dst] = -count[e.dst] + 1; + que.push(e.dst); + } + } + } + } + } else { // use Dijkstra + typedef pair node; + priority_queue, greater> que; + que.push({0, s}); + while (!que.empty()) { + node a = que.top(); que.pop(); + if (a.snd == t) break; + if (dist[a.snd] > a.fst) continue; + for (auto e: adj[a.snd]) { + if (e.capacity > e.flow && dist[e.dst] > a.fst + rcost(e)) { + dist[e.dst] = dist[e.src] + rcost(e); + prev[e.dst] = e.rev; + que.push({dist[e.dst], e.dst}); + } + } + } + } + if (prev[t] == -1) break; + + for (int u = 0; u < n; ++u) + if (dist[u] < dist[t]) p[u] += dist[u] - dist[t]; + + function augment = [&](int u, flow_type cur) { + if (u == s) return cur; + edge &r = adj[u][prev[u]], &e = adj[r.dst][r.rev]; + flow_type f = augment(e.src, min(e.capacity - e.flow, cur)); + e.flow += f; r.flow -= f; + return f; + }; + flow_type f = augment(t, INF); + flow += f; + cost += f * (p[t] - p[s]); + } + return {flow, cost}; + } +}; +} + + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + + +int main() { + for (int seed = 0; seed < 10000; ++seed) { + cout << "--------------------" << endl; + + cout << "seed = " << seed << endl; + srand(seed); + + int n = 200; + Tomizawa_Edmonds_Karp::graph g1(n); + NegativeCycleCanceling::graph g2(n); + + /* + g2.add_edge(0, 1, 1, 1); + g2.add_edge(1, 2, 1, 1); + g2.add_edge(2, 3, 1, 1); + g2.add_edge(1, 3, 1, 4); + */ + /* + g2.add_edge(0, 1, 1, 1); + g2.add_edge(1, 2, 1, 1); + g2.add_edge(2, 3, 1, 1); + g2.add_edge(1, 3, 1, 1); + */ + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (i == j) continue; + if (rand() % 2 == 0) { + int a = 1 + rand() % 10; + int b = 1 + rand() % 10; + g1.add_edge(i, j, a, b); + g2.add_edge(i, j, a, b); + } + } + } + + int s = 0, t = n-1; + tick(); + auto a = g1.min_cost_max_flow(s, t); + cout << a.fst << " " << a.second << " " << tick() << endl; + auto b = g2.min_cost_max_flow(s, t); + cout << b.fst << " " << b.second << " " << tick() << endl; + if (a.snd != b.snd) break; + } +} From c51bcb64748b9e9c7cf72f27990ed719ac51ff12 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 9 Jun 2016 08:12:52 +0900 Subject: [PATCH 045/141] Minimum Cost Maximum Flow (Tomizawa, Edmonds-Karp's successive shortest path) --- ...c => minimum_cost_maximum_flow_tomizawa_edmonds_karp_ssp.cc} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename graph/{minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc => minimum_cost_maximum_flow_tomizawa_edmonds_karp_ssp.cc} (98%) diff --git a/graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc b/graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp_ssp.cc similarity index 98% rename from graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc rename to graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp_ssp.cc index e5a1fcf..5155d15 100644 --- a/graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp.cc +++ b/graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp_ssp.cc @@ -1,5 +1,5 @@ // -// Minimum Cost Maximum Flow (Tomizawa, Edmonds-Karp) +// Minimum Cost Maximum Flow (Tomizawa, Edmonds-Karp's successive shortest path) // // Description: // Given a directed graph G = (V,E) with nonnegative capacity c and cost w. From 2c771e1be8b2c5385da61bd354af3c4ad36884e2 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 9 Jun 2016 08:15:54 +0900 Subject: [PATCH 046/141] Update README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 871386c..e2760a9 100644 --- a/README.md +++ b/README.md @@ -96,8 +96,12 @@ This category should be reorganized. - graph/link_cut_tree.cc - graph/maximal_cliques.cc - graph/maximum_cut.cc -- graph/maximum_flow_dinic.cc -- graph/maximum_flow_ford_fulkerson.cc +- [Maximum Flow (Ford-Fulkerson)](graph/maximum_flow_ford_fulkerson.cc) +- [Maximum Flow (Edmonds-Karp)](graph/maximum_flow_edmonds_karp.cc) +- [Maximum Flow (Dinic's blocking flow)](graph/maximum_flow_dinic.cc) +- [Maximum Flow (Goldberg-Tarjan's preflow-push)](graph/maximum_flow_goldberg_tarjan.cc) +- [Minimum Cost Maximum Flow (Tomizawa, Edmonds-Karp's successive shortest paths](graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp_ssp.cc) +- [Minimum Cost Maximum Flow (Goldberg-Tarjan's minimum mean cycle canceling](graph/minimum_cost_maximum_flow_goldberg_tarjan_mmcc.cc) - graph/minimum_feedback_arc_set.cc - graph/minimum_mean_cycle.cc - graph/reachability.cc @@ -105,7 +109,7 @@ This category should be reorganized. - graph/strongly_connected_component_gabow.cc - graph/strongly_connected_component_kosaraju.cc - graph/strongly_connected_component_tarjan.cc -- graph/tomizawa_edmonds_karp.cc + - graph/transitive_reduction_dag.cc - graph/traveling_salesman.cc - graph/tree_decomposition.cc From d856cc1c6ae76750dff0d7ff11b6ab6048b1a694 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 15 Jun 2016 21:30:43 +0900 Subject: [PATCH 047/141] Numerical derivative (Ridder's method) --- math/derivative.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 math/derivative.cc diff --git a/math/derivative.cc b/math/derivative.cc new file mode 100644 index 0000000..9b700bd --- /dev/null +++ b/math/derivative.cc @@ -0,0 +1,58 @@ +// +// Numerical Derivative by Ridder's method. +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +double differentiate(F f, double x, double eps = 1e-8) { + const int n = 10; + const double alpha = 1.4; + double h = 1e-2, a[n][n], ans = 1.0/0.0, err = 1.0/0.0; + + a[0][0] = (f(x + h) - f(x - h)) / (2 * h); + for (int i = 1; i < n; ++i) { + h /= alpha; + a[0][i] = (f(x + h) - f(x - h))/(2 * h); + double fac = alpha * alpha; + for (int j = 1; j <= i; ++j) { + a[j][i] = (a[j-1][i] * fac - a[j-1][i-1])/(fac - 1.0); + fac *= alpha * alpha; + double errt = max(fabs(a[j][i] - a[j-1][i]), fabs(a[j][i] - a[j-1][i-1])); + if (errt <= err) { + err = errt; + ans = a[j][i]; + if (err < eps) return ans; + } + } + if (fabs(a[i][i] - a[i-1][i-1]) >= 2 * err) break; + } + return ans; +} + +double f(double x) { + return exp(-x*x); +} +double df(double x) { + return -2 * x * exp(-x*x); +} + +int main() { + for (int i = 0; i < 10; ++i) { + double x = rand() / (1.0 + RAND_MAX); + cout << differentiate(f, x) - df(x) << endl; + } +} + From fdc02eb2f3ef8d8540826396a06007c8483859fb Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 15 Jun 2016 22:12:52 +0900 Subject: [PATCH 048/141] equivalence class --- __WIP/equivalence.cc | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 __WIP/equivalence.cc diff --git a/__WIP/equivalence.cc b/__WIP/equivalence.cc new file mode 100644 index 0000000..b0dbd2f --- /dev/null +++ b/__WIP/equivalence.cc @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +// specify operator == +template +void equivalence(vector x, F eq) { + vector parent(x.size()); + for (int i = ; i < x.size(); ++i) { + parent[i] = i; + for (int j = 0; j < i; ++j) { + parent[j] = parent[parent[j]]; + if (eq(x[i], x[j])) parent[parent[parent[j]]] = i; + } + } + for (int i = 0; i < x.size(); ++i) parent[i] = parent[parent[i]]; + + for (int i = 0; i < parent.size(); ++i) + printf("%d %d \n", x[i], parent[i]); +} + +int main() { + vector x = {3,1,4,1,5,9,2,6,5,3,5,8,9}; + equivalence(x, [&](int a, int b) { return a == b; }); +} From fdd1ddd139618a2754602dd5effbd90ee464b3a3 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 22 Jun 2016 00:56:47 +0900 Subject: [PATCH 049/141] Nelder Mead method (aka. Downhill Simplex Method) --- math/nelder_mead.cc | 178 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 math/nelder_mead.cc diff --git a/math/nelder_mead.cc b/math/nelder_mead.cc new file mode 100644 index 0000000..f48bb0d --- /dev/null +++ b/math/nelder_mead.cc @@ -0,0 +1,178 @@ +// +// Nelder Mead method (aka. Downhill Simplex Method) +// +// Description: +// Nelder Mead method is a first-order optimization method +// that only requires function evaluation oracle. +// Typically, it performs well on a function on a small +// dimensional space. +// +// Algorithm: +// Consider a simplex on the domain. +// Evaluate function values on each vertex, +// and replace the vertices according to some rules. +// See the reference. +// +// Reference: +// Fuchang Gao and Lixing Han (2010): +// Implementing the Nelder-Mead simplex algorithm with adaptive parameters. +// Computational Optimization and Applications, vol.51, no.1, pp.259--277. +// +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + + +#include +using namespace std; + +template +vector operator+(vector x, vector y) { + for (int i = 0; i < y.size(); ++i) x[i] += y[i]; + return x; +} +template +vector operator-(vector x, vector y) { + for (int i = 0; i < y.size(); ++i) x[i] -= y[i]; + return x; +} +template +vector operator*(T a, vector x) { + for (int i = 0; i < x.size(); ++i) x[i] *= a; + return x; +} + + +template +ostream &operator<<(ostream &os, const vector &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << " "; + os << "]"; + return os; +} +template +ostream &operator<<(ostream &os, const vector> &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << endl << " "; + os << "]"; + return os; +} + +const double EPS = 1e-8; +template +pair> minimize(F f, vector x0, double R = 100) { + const int n = x0.size(); + const double alpha = 1.0, beta = 1.0 + 2.0/n, + gamma = 0.75 - 1.0/(2.0 * n), delta = 1.0 - 1.0/n; + + vector> xs = {x0}; + vector fs = {f(x0)}; + vector ord(n+1); + for (int i = 1; i <= n; ++i) { + xs.push_back(x0); + xs[i][i-1] += (x0[i-1] == 0.0 ? 0.00025 : 0.05); + fs.push_back(f(xs[i])); + ord[i] = i; + } + sort(all(ord), [&](int i, int j) { return fs[i] < fs[j]; }); + + auto centroid = [&]() { + vector x(n); + for (int i = 0; i <= n; ++i) + if (i != ord[n]) x = x + xs[i]; + return (1.0/n)*x; + }; + vector c = centroid(); + + for (int iter = 0; iter < 10000; ++iter) { + auto replace = [&](vector x, double v) { + xs[ord[n]] = x; fs[ord[n]] = v; + int j = n, k = ord[n]; + for (; j > 0 && fs[ord[j-1]] > fs[k]; --j) + ord[j] = ord[j-1]; + ord[j] = k; + c = c + (1.0 / n) * (x - xs[ord[n]]); + }; + auto shrink = [&]() { + for (int i = 1; i <= n; ++i) { + xs[i] = xs[0] + delta * (xs[i] - xs[0]); + fs[i] = f(xs[i]); + } + sort(all(ord), [&](int i, int j) { return fs[i] < fs[j]; }); + c = centroid(); + }; + auto run = [&]() { + auto xr = c + alpha * (c - xs[ord[n]]); + auto fr = f(xr); + if (fr < fs[ord[0]]) { + auto xe = c + beta * (xr - c); + auto fe = f(xe); + if (fe < fr) return replace(xe, fe); + else return replace(xr, fr); + } + if (fr <= fs[ord[n-1]]) return replace(xr, fr); + auto xc = c + (fr > fs[ord[n]] ? -gamma : gamma) * (xr - c); + auto fc = f(xc); + if (fc <= fr) return replace(xc, fc); + else return shrink(); + }; run(); + auto conv = [&]() { // conversion check + for (int i = 0; i <= n; ++i) { + if (fs[i] >= fs[ord[0]] + EPS) return false; + for (int j = 0; j < n; ++j) + if (fabs(xs[i][j] - xs[ord[0]][j]) >= EPS) return false; + } + return true; + }; if (conv()) break; + } + return {fs[ord[0]], xs[ord[0]]}; +} + +double rosenbrock(vector x){ + return (1.0 - x[0])*(1.0 - x[0]) + + 100 * (x[1] - x[0]*x[0]) * (x[1] - x[0]*x[0]); +} +double beale(vector x) { + return pow(1.5-x[0]+x[0]*x[1],2) + pow(2.25-x[0]+x[0]*x[1]*x[1],2) + pow(2.625-x[0]+x[0]*x[1]*x[1]*x[1], 2); +} +double bukin(vector x) { + return 100 * sqrt(fabs(x[1] - 0.01 * x[0]*x[0])) + 0.01 * fabs(x[0] + 10); +} +double egg_holder(vector x) { + return -(x[1]+47)*sin(sqrt(fabs(x[0]/2+(x[1]+47)))) - x[0]*sin(sqrt(fabs(x[0] - (x[1]+47)))); +} +double holder_table(vector x) { + return -fabs(sin(x[0])*cos(x[1])*exp(fabs(1 - sqrt(x[0]*x[0]+x[1]*x[1])/M_PI))); +} + +int main() { + vector x = {0, 0}; + auto ans = minimize(rosenbrock, x); + cout << ans.fst << " at " << ans.snd << endl; + + ans = minimize(beale, x); + cout << ans.fst << " at " << ans.snd << endl; + + x = {-11, 2}; + ans = minimize(bukin, x); + cout << ans.fst << " at " << ans.snd << endl; + + ans = minimize(egg_holder, x); + cout << ans.fst << " at " << ans.snd << endl; + + x = {8, 9}; + ans = minimize(holder_table, x); + cout << ans.fst << " at " << ans.snd << endl; +} From 088c447f8dc4042311bd4fbeec456715d0bfc0f0 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 29 Jun 2016 21:30:25 +0900 Subject: [PATCH 050/141] Proof Number Search (successive DFS) --- game/proof_number_search.cc | 189 ++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 game/proof_number_search.cc diff --git a/game/proof_number_search.cc b/game/proof_number_search.cc new file mode 100644 index 0000000..81d541b --- /dev/null +++ b/game/proof_number_search.cc @@ -0,0 +1,189 @@ +// +// Proof Number Search +// +// Description: +// Proof number search is search algorithm used in two-player endgame. +// It is a best-first search that expands most provable nodes. +// +// Note: +// It is slow if deciding win/lose is difficult until the playout. +// (in this case, naive search may outperform) +// +// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +// 0 1 2 3 +// 4 5 6 7 +// 8 9 10 11 +// 12 13 14 15 + +struct state { + int p, T[16], status; + state() { + p = +1; + for (int i = 0; i < 16; ++i) + T[i] = 0; + } + + // must implement + // terminal: +1 (alice win) or -1 (bob win) + // non-terminal: 0 + int eval() { + const vector> lines = { + {0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}, + {0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}, + {0,5,10,15},{3,6,9,12} + /* + {0,1,2}, {1,2,3}, {4,5,6}, {5,6,7}, + {8,9,10}, {9,10,11}, {12,13,14}, {13,14,15}, + {0,4,8}, {4,8,12}, {1,5,9}, {5,9,13}, + {2,6,10}, {6,10,14}, {3,7,11}, {7,11,15}, + {0,5,10}, {1,6,11}, {2,5,8}, {3,6,9}, + {4,9,14}, {5,10,15}, {6,9,12}, {7,10,13} + */ + }; + for (int i = 0; i < lines.size(); ++i) { + bool same = true; + for (int j = 1; j < lines[i].size(); ++j) + if (T[lines[i][0]] != T[lines[i][j]]) same = false; + if (same && T[lines[i][0]]) return T[lines[i][0]]; + } + int free = 0; + for (int i = 0; i < 16; ++i) + free += T[i] == 0; + if (free == 0) return -1; + return 0; + } + + // must implement + vector next() const { + vector ss; + for (int i = 0; i < 16; ++i) { + if (T[i] == 0) { + state t(*this); + t.T[i] = t.p; t.p = -t.p; + ss.push_back(t); + } + } + return ss; + } + // must implement + bool operator == (const state &s) const { + for (int i = 0; i < 16; ++i) + if (T[i] != s.T[i]) return false; + return true; + } + + void disp() { + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + printf("%c ", T[4*i+j] > 0 ? 'o' : T[4*i+j] < 0 ? 'x' : '.'); + } + printf("\n"); + } + } + +}; + +// must implement +namespace std { + template <> + struct hash { + size_t operator()(const state &s) const { + size_t h = 0; + for (int i = 0; i < 16; ++i) + h = 4 * h + (s.T[i] + 1); + return h; + } + }; +}; + +int cached_search(state s) { + unordered_map cache; + function rec = [&](state &s) { + if (cache.count(s)) return cache[s]; + int eval = s.eval(); + if (eval) return eval; + for (state t: s.next()) { + if (rec(t) == s.p) return cache[s] = s.p; + } + return cache[s] = -s.p; + }; + int ret = rec(s); + cout << ret << " / opened nodes = " << cache.size() << endl; + return 0; +} + +const int INF = 99999999; +bool proof_number_search(state root) { + vector states; + + unordered_map pn, dn; + unordered_set expanded; + + function augment = [&](state s) { + // foward expand + vector next = s.next(); + if (!expanded.count(s)) { + expanded.insert(s); + for (state t: next) { + if (pn.count(t)) continue; + auto eval = t.eval(); + if (eval) { + expanded.insert(t); + if (eval > 0) { pn[t] = 0; dn[t] = INF; } + else { pn[t] = INF; dn[t] = 0; } + } else { + pn[t] = dn[t] = 1; + } + } + } else { + if (!next.empty()) { + state t = next[0]; + for (int i = 1; i < next.size(); ++i) + if (s.p == +1 && pn[t] > pn[next[i]]) t = next[i]; + else if (s.p == -1 && dn[t] > dn[next[i]]) t = next[i]; + augment(t); + } + } + // backward update + if (s.p == +1) { + pn[s] = INF; dn[s] = 0; + for (state t: next) { + pn[s] = min(pn[s], pn[t]); + dn[s] += dn[t]; + } + } else { + pn[s] = 0; dn[s] = INF; + for (state t: next) { + pn[s] += pn[t]; + dn[s] = min(dn[s], dn[t]); + } + } + }; + pn[root] = dn[root] = 1; + int iter = 0; + while (pn[root] > 0 && dn[root] > 0) augment(root); + //cout << "number of expanded nodes: " << expanded.size() << endl; + return pn[root] == 0; +} + +int main() { + state s; + cout << cached_search(s) << endl; + cout << proof_number_search(s) << endl; +} From 20bfef2a2fcdf101826acf7d875a85b5bc599fb6 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 30 Jun 2016 16:02:17 +0900 Subject: [PATCH 051/141] Biconnected components and Articulation points (Hopcroft-Tarjan) --- graph/articulation_points.cc | 69 +++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/graph/articulation_points.cc b/graph/articulation_points.cc index 8e756c3..07c5dd0 100644 --- a/graph/articulation_points.cc +++ b/graph/articulation_points.cc @@ -5,13 +5,21 @@ // Let G = (V, E). If G-v is disconnected, v in V is said to // be an articulation point. If G has no articulation points, // it is said to be biconnected. +// // A biconnected component is a maximal biconnected subgraph. // The algorithm finds all articulation points and biconnected // components. // +// The most important fact is that by contracting biconnected +// components we obtain a tree, which is called the block tree. +// +// // Algorithm: // Hopcroft-Tarjan's DFS based algorithm. // +// Single DFS finds a block tree rooted from the component +// that contains the specified root. +// // Complexity: // O(n + m). // @@ -46,36 +54,39 @@ struct graph { adj[src].push_back(dst); adj[dst].push_back(src); } -}; -void biconnected_components(graph g) { - vector arts(g.n), num(g.n), low(g.n), S; - vector> comps; - function dfs = [&](int p, int i, int &t) { - num[i] = low[i] = ++t; - S.push_back(i); - for (int j: g.adj[i]) { - if (j == p) continue; - if (num[j] == 0) { - dfs(i, j, t); - low[i] = min(low[i], low[j]); - if (num[i] <= low[j]) { - if (num[i] != 1 || low[j] > 2) arts[i] = true; - for (comps.push_back({i}); comps.back().back() != j; S.pop_back()) - comps.back().push_back(S.back()); // - } - } else low[i] = min(low[i], num[j]); - } - }; - for (int i = 0, t; i < g.n; ++i) - if (num[i] == 0) dfs(-1, i, t = 0); + void biconnected_components() { + vector num(n), low(n), S; + unordered_set arts; - // SPOJ SUBMERGE - int count = 0; - for (int i = 0; i < g.n; ++i) - count += arts[i]; - printf("%d\n", count); -} + function dfs = [&](int p, int u, int &t) { + num[u] = low[u] = ++t; + S.push_back(u); + for (int v: adj[u]) { + if (v == p) continue; + if (num[v] == 0) { + dfs(u, v, t); + low[u] = min(low[u], low[v]); + if (num[u] <= low[v]) { + if (num[u] != 1 || num[v] > 2) { + // here, u is an articulation point if + // (a). u is non-root + // (b). u is root with two more children + } + vector C = {u}; // biconnected component + while (C.back() != v) { + C.push_back(S.back()); + S.pop_back(); + } + } + } else low[u] = min(low[u], num[v]); + } + }; + for (int u = 0, t; u < n; ++u) + if (!num[u]) dfs(-1, u, t = 0); + cout << arts.size() << endl; + } +}; int main() { for (int n, m; ~scanf("%d %d", &n, &m) && n; ) { @@ -84,6 +95,6 @@ int main() { int u, v; scanf("%d %d", &u, &v); g.add_edge(u-1, v-1); } - biconnected_components(g); + g.biconnected_components(); } } From c0d175dea9a67c651e36355e106316af1672a347 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 1 Jul 2016 19:58:39 +0900 Subject: [PATCH 052/141] Grundy number of Green Hackenbush --- game/green_hackenbush.cc | 110 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 game/green_hackenbush.cc diff --git a/game/green_hackenbush.cc b/game/green_hackenbush.cc new file mode 100644 index 0000000..72117a3 --- /dev/null +++ b/game/green_hackenbush.cc @@ -0,0 +1,110 @@ +// +// Green Hackenbush +// +// Description: +// Consider a two player game on a graph with a specified vertex (root). +// In each turn, a player eliminates one edge. +// Then, if a subgraph that is disconnected from the root, it is removed. +// If a player cannot select an edge (i.e., the graph is singleton), +// he will lose. +// +// Compute the Grundy number of the given graph. +// +// Algorithm: +// We use two principles: +// 1. Colon Principle: Grundy number of a tree is the xor of +// Grundy number of child subtrees. +// (Proof: easy). +// +// 2. Fusion Principle: Consider a pair of adjacent vertices u, v +// that has another path (i.e., they are in a cycle). Then, +// we can contract u and v without changing Grundy number. +// (Proof: difficult) +// +// We first decompose graph into two-edge connected components. +// Then, by contracting each components by using Fusion Principle, +// we obtain a tree (and many self loops) that has the same Grundy +// number to the original graph. By using Colon Principle, we can +// compute the Grundy number. +// +// Complexity: +// O(m + n). +// +// Verified: +// SPOJ 1477: Play with a Tree +// IPSC 2003 G: Got Root? +// +// +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct hackenbush { + int n; + vector> adj; + + hackenbush(int n) : n(n), adj(n) { } + void add_edge(int u, int v) { + adj[u].push_back(v); + if (u != v) adj[v].push_back(u); + } + + // r is the only root connecting to the ground + int grundy(int r) { + vector num(n), low(n); + int t = 0; + function dfs = [&](int p, int u) { + num[u] = low[u] = ++t; + int ans = 0; + for (int v: adj[u]) { + if (v == p) { p += 2*n; continue; } + if (num[v] == 0) { + int res = dfs(u, v); + low[u] = min(low[u], low[v]); + if (low[v] > num[u]) ans ^= (1 + res) ^ 1; // bridge + else ans ^= res; // non bridge + } else low[u] = min(low[u], num[v]); + } + if (p > n) p -= 2*n; + for (int v: adj[u]) + if (v != p && num[u] <= num[v]) ans ^= 1; + return ans; + }; + return dfs(-1, r); + } +}; + +int main() { + int cases; scanf("%d", &cases); + for (int icase = 0; icase < cases; ++icase) { + int n; scanf("%d", &n); + vector ground(n); + int r; + for (int i = 0; i < n; ++i) { + scanf("%d", &ground[i]); + if (ground[i] == 1) r = i; + } + int ans = 0; + hackenbush g(n); + for (int i = 0; i < n-1; ++i) { + int u, v; + scanf("%d %d", &u, &v); + --u; --v; + if (ground[u]) u = r; + if (ground[v]) v = r; + if (u == v) ans ^= 1; + else g.add_edge(u, v); + } + int res = ans ^ g.grundy(r); + printf("%d\n", res != 0); + } +} From e255c7b345d2313278eb2acfb9ad2db107edded7 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 2 Jul 2016 18:10:08 +0900 Subject: [PATCH 053/141] 15 Puzzle by IDA* with Disjoint Pattern Database --- game/15puzzle.cc | 221 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 game/15puzzle.cc diff --git a/game/15puzzle.cc b/game/15puzzle.cc new file mode 100644 index 0000000..803813b --- /dev/null +++ b/game/15puzzle.cc @@ -0,0 +1,221 @@ +// +// Fifteen Puzzle (IDA* with disjoint pattern database heuristics) +// + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +const int INF = 9999999; + +// 16 is for blank tile, 0 is for abstracted tiles +// +// 1 2 3 4 +// 5 6 7 8 +// 9 10 11 12 +// 13 14 15 16 +// +struct state { + int p, T[16]; + long long hash_value, pow[16]; + const long long P = 17, M = 1e9+7; + state(vector T_) { + copy(T_.begin(), T_.end(), T); + for (p = 0; T[p] != 16; ++p); + + pow[0] = 1; + for (int i = 0; i < 15; ++i) + pow[i+1] = (pow[i] * P) % M; + hash_value = 0; + for (int i = 0; i < 16; ++i) + hash_value = (hash_value + pow[i] * T[i]) % M; + } + + bool move(int d) { // (d + 2) % 4 is reverse direction of d + int q; + if (d == 0) { + if (p % 4 == 0) return false; + q = p - 1; + } else if (d == 1) { + if (p < 4) return false; + q = p - 4; + } else if (d == 2) { + if (p % 4 == 3) return false; + q = p + 1; + } else { + if (p >= 12) return false; + q = p + 4; + } + hash_value -= (pow[p]*T[p] + pow[q]*T[q]); + swap(T[p], T[q]); + hash_value += (pow[p]*T[p] + pow[q]*T[q]); + while (hash_value < 0) hash_value += M; + while (hash_value >= M) hash_value -= M; + p = q; + return true; + } + + bool operator == (const state &s) const { + for (int i = 0; i < 16; ++i) + if (T[i] != s.T[i]) return false; + return true; + } + + void disp() { + for (int i = 0; i < 16; ++i) { + printf(" %2d", T[i]); + if (i % 4 == 3) printf("\n"); + } + } +}; +namespace std { + template <> + struct hash { + size_t operator()(const state &s) const { + return s.hash_value; + } + }; +} +// 16 is for blank tile, 0 is for abstracted tiles +// +// 1 2 3 4 +// 5 6 7 8 +// 9 10 11 12 +// 13 14 15 16 +// + +vector> pat = { + /* + {0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1}, + {0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1}, + */ + /* + {0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1}, + {0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1} + */ + /* + {0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1}, + {0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1}, + {0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1}, + {0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1} + */ + {0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1}, + {0,0,0,1,1,0,0,1,1,0,0,0,1,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1}, +}; +vector> ph(pat.size()); + +void pattern_database(vector pat, unordered_map &ph) { + fprintf(stderr, "construting pattern database\n"); + vector goal = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; + for (int i = 0; i < 16; ++i) + if (!pat[goal[i]]) goal[i] = 0; + queue que; + que.push(goal); + ph[goal] = 0; + + while (!que.empty()) { + state s = que.front(); que.pop(); + int c = ph[s]; + for (int d = 0; d < 4; ++d) { + int p = s.p; + if (s.move(d)) { + if (!ph.count(s)) { + ph[s] = c + (pat[s.T[p]] != 0); + que.push(s); + } + s.move((d+2)%4); + } + } + } + fprintf(stderr, "done constructing pattern database, size %zd\n", ph.size()); +} + + +int manhattan_heuristics(state s) { + // for comparison + int d = 0; + for (int k = 0; k < 16; ++k) { + int a = s.T[k] - 1; + if (s.T[k] != 16) d += abs(a%4 - k%4) + abs(a/4 - k/4); + } + return d; +} + +int pattern_database_heuristics(state s) { + int d = 0; + for (int k = 0; k < pat.size(); ++k) { + vector T(s.T, s.T+16); + for (int i = 0; i < 16; ++i) + if (!pat[k][T[i]]) T[i] = 0; + state t(T); + d += ph[k][t]; + } + return d; +} + +int ida_star(state s) { + int bound, opened = 0; + function rec = [&](state &s, int depth, int prev) { + ++opened; + //int h = manhattan_heuristics(s); + int h = pattern_database_heuristics(s); + if (h == 0) return true; + if (depth < h) return false; + for (int d = 0; d < 4; ++d) { + if ((d + 2) % 4 == prev) continue; + if (s.move(d)) { + if (rec(s, depth-1, d)) return true; + s.move((d + 2) % 4); + } + } + return false; + }; + for (bound = 0; !rec(s, bound, 100); ++bound) { + printf("%d\n", bound); + } + printf("%d\n", bound); + printf("opened nodes = %d\n", opened); + return 0; +} + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +int main() { + + for (int k = 0; k < pat.size(); ++k) + pattern_database(pat[k], ph[k]); + + vector idx = {2,3,1,4,5,16,11,8,9,7,10,12,13,14,6,15}; + //vector idx = {1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16}; // <- very difficult + + state s(idx); + tick(); + ida_star(s); + // manhattan: opened nodes = 101622 + // 3-4-4-4 pattern: opened nodes = 9946 + // 3-3-3-3-3 pattern: opened nodes = 7003 + // 5-5-5 pattern: opened nodes = 1691 + printf("%f\n", tick()); +} From ce3d935554c57b1dab9e47119be9a3c9886db2fc Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 3 Jul 2016 07:24:19 +0900 Subject: [PATCH 054/141] Alpha Beta Pruning with Transposition Table (Tic-Tac-Toe) --- game/alphabeta.cc | 155 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 game/alphabeta.cc diff --git a/game/alphabeta.cc b/game/alphabeta.cc new file mode 100644 index 0000000..179d059 --- /dev/null +++ b/game/alphabeta.cc @@ -0,0 +1,155 @@ +// +// Alpha-Beta Pruning with Transposition Table (Tic-Tac-Toe) +// +// Description: +// Alpha-Beta pruning finds the game value of the state +// under the condition of "in [alpha, beta)". +// Transposition table memoises states in the search tree. +// +// Algorithm +// The basic code for fail-soft alpha-beta pruning is given as +// +// def alphabeta(s, alpha, beta): +// if s is a terminate node: +// return s.score +// low = -inf +// for each t: child of s +// low = max(low, -alphabeta(t, -beta, -max(alpha,low))) +// if low >= beta: break +// return low +// +// Here, fail-soft means it always returns a realizable value. +// This implementation is suitable for memoisation. +// +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +const int w = 3, n = 9; +struct state { + int p, T[n]; + + state() { + p = +1; + for (int i = 0; i < 9; ++i) + T[i] = 0; + } + + // must implement. + // return the board status (finished or not) + // and set board score into score variable + // (player p win ==> positive + // lose ==> negative ) + int score; + bool finished() { + const vector> lines = { + {0,1,2},{3,4,5},{6,7,8}, + {0,3,6},{1,4,7},{2,5,8}, + {0,4,8},{2,4,6} + }; + score = n; + for (int i = 0; i < n; ++i) + if (T[i] != 0) --score; + if (score == 0) return true; + for (int i = 0; i < lines.size(); ++i) { + bool same = true; + for (int j = 1; j < lines[i].size(); ++j) + if (T[lines[i][0]] != T[lines[i][j]]) same = false; + if (same && T[lines[i][0]]) { + score += 100; if (T[lines[i][0]] != p) score *= -1; + return true; + } + } + return false; + } + void disp() { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + printf("%c ", T[3*i+j] > 0 ? 'o' : T[3*i+j] < 0 ? 'x' : '.'); + } + printf("\n"); + } + } + // must implement + bool operator == (const state &s) const { + for (int i = 0; i < 9; ++i) + if (T[i] != s.T[i]) return false; + return true; + } +}; +// must implement +namespace std { + template <> + struct hash { + size_t operator()(const state &s) const { + size_t h = 0; + for (int i = 0; i < 9; ++i) + h = 4 * h + (s.T[i] + 1); + return h; + } + }; +}; + +const int INF = 99999999; +unordered_map cache; +pair alphabeta(state s, int alpha, int beta) { + int move = -1; + if (s.finished()) return {s.score, move}; + int low = (cache.count(s) ? cache[s] : -INF); + + for (int k = 0; k < 9; ++k) { + if (s.T[k]) continue; + s.T[k] = s.p; s.p = -s.p; + auto ans = alphabeta(s, -beta, -max(alpha,low)); + s.T[k] = 0; s.p = -s.p; + if (low <= -ans.fst) { + low = -ans.fst; + move = k; + } + if (low >= beta) break; + } + return {cache[s] = low, move}; +} + + +int main() { + state s; + alphabeta(s, -INF, INF); + cout << cache.size() << endl; + + int player = +1; + while (1) { + s.disp(); + if (s.finished()) { + if (s.score == 0) cout << "game is draw" << endl; + else { + if (s.p > 0) cout << "player +1 " << (s.score > 0 ? "win" : "lose") << endl; + else cout << "player -1 " << (s.score < 0 ? "lose" : "win") << endl; + } + break; + } + if (s.p == player) { + int k; + while (1) { + cin >> k; + if (s.T[k] == 0) break; + } + s.T[k] = s.p; s.p = -s.p; + } else { + auto ans = alphabeta(s, -INF, INF); + cout << ans.fst << endl; + int k = ans.snd; + s.T[k] = s.p; s.p = -s.p; + } + } +} From 67c285249574de88db7c3441bdac3d4cbfa0f9c7 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 8 Jul 2016 17:28:12 +0900 Subject: [PATCH 055/141] Big Integer --- math/bigint.cci | 228 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 math/bigint.cci diff --git a/math/bigint.cci b/math/bigint.cci new file mode 100644 index 0000000..715fd4b --- /dev/null +++ b/math/bigint.cci @@ -0,0 +1,228 @@ +// +// Big Integer +// +// Description +// comparison O(n) +// addition, subtraction O(n) +// multiplication O(n^{1.7}): Karatsuba +// division O(n^2): Knuth' D +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using namespace std; + +// tick a time +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +struct bigint : vector { + // smaller B ==> larger deals / slower operations + // B = 100000000 (10^8) ==> it deals with 10^645636 + // B = 1000000000 (10^9) ==> it deals with 10^7378 + static constexpr int B = 1000000, W = log10(B); + char sign; + bigint& trim() { + while (!empty() && !back()) pop_back(); + if (empty()) sign = 1; + return *this; + } + bigint(long long v = 0) : sign(1) { + if (v < 0) { sign = -1; v = -v; } + while (v > 0) { + push_back(v % B); + v /= B; + } + } + bigint(string s) : sign(+1) { + int e = 0; + for (; e < s.size() && s[e] <= '0' || s[e] >= '9'; ++e) + if (s[e] == '-') sign = -sign; + for (int i = s.size()-1; i >= e; i -= W) { + push_back(0); + for (int j = max(e, i - W + 1); j <= i; ++j) + back() = 10 * back() + (s[j] - '0'); + } + trim(); + } + bigint operator-() const { + bigint x = *this; + if (!empty()) x.sign = -x.sign; + return x; + } + operator vector(); // protect from unexpected casts + + bigint &operator+=(bigint x); +}; + +// input and output +ostream &operator<<(ostream &os, const bigint &x) { + if (x.sign < 0) os << '-'; + os << (x.empty() ? 0 : x.back()); + for (int i = (int)x.size()-2; i >= 0; --i) + os << setfill('0') << setw(bigint::W) << x[i]; + return os; +} +istream &operator>>(istream &is, bigint &x) { + string s; + is >> s; + x = bigint(s); + return is; +} + +bigint operator-(bigint x, bigint y); +bigint operator+(bigint x, bigint y) { + if (x.sign != y.sign) return x - (-y); + if (x.size() < y.size()) swap(x, y); + int c = 0; + for (int i = 0; i < y.size(); ++i) { + x[i] += y[i] + c; + c = (x[i] >= bigint::B); + if (c) x[i] -= bigint::B; + } + if (c) x.push_back(c); + return x; +} +bigint operator-(bigint x, bigint y) { + if (x.sign != y.sign) return x + (-y); + int sign = x.sign; + x.sign = y.sign = +1; + if (x < y) { + swap(x, y); + sign = -sign; + } + int c = 0; + for (int i = 0; i < x.size(); ++i) { + x[i] -= (i < y.size() ? y[i] : 0) + c; + c = (x[i] < 0); + if (c) x[i] += bigint::B; + } + x.sign = sign; + return x.trim(); +} +bigint operator*(bigint x, int y) { + if (y == 0) return bigint(0); + if (y < 0) { x.sign = -x.sign; y = -y; } + int c = 0; + for (int i = 0; i < x.size() || c; ++i) { + if (i == x.size()) x.push_back(0); + x[i] = x[i] * y + c; + c = x[i] / bigint::B; + if (c) x[i] %= bigint::B; + } + return x; +} +bigint operator*(int x, bigint y) { return y * x; } + +// Karatsuba multiplication +bigint operator*(bigint x, bigint y) { + if (x.empty()||y.empty()) return bigint(0); + function + rec = [&](long long *x, int xn, long long *y, int yn, long long *z) { + if (xn < yn) { swap(xn, yn); swap(x, y); } + fill(z, z+xn+yn, 0); + if (yn <= 2) { + for (int i = 0; i < xn; ++i) + for (int j = 0; j < yn; ++j) + z[i+j] += x[i] * y[j]; + } else { + int m = (xn+1)/2, n = min(m, yn); + for (int i = 0; i+m < xn; ++i) x[i] += x[i+m]; + for (int j = 0; j+m < yn; ++j) y[j] += y[j+m]; + rec(x, m, y, n, z+m); + for (int i = 0; i+m < xn; ++i) x[i] -= x[i+m]; + for (int j = 0; j+m < yn; ++j) y[j] -= y[j+m]; + long long p[2*m+2]; + rec(x, m, y, n, p); + for (int i = 0; i < m+n; ++i) { z[i] += p[i]; z[i+m] -= p[i]; } + rec(x+m, xn-m, y+m, yn-n, p); + for (int i = 0; i < xn+yn-m-n; ++i) { z[i+m] -= p[i]; z[i+2*m] += p[i]; } + } + }; + bigint z; z.resize(x.size()+y.size()+2); + z.sign = x.sign * y.sign; + rec(&x[0], x.size(), &y[0], y.size(), &z[0]); + for (int i = 0; i+1 < z.size(); ++i) { // be careful with overflow + z[i+1] += z[i] / bigint::B; + z[i] %= bigint::B; + if (z[i] < 0) { + z[i+1] -= 1; + z[i] += bigint::B; + } + } + return z.trim(); +} +bigint pow(bigint x, int b) { + bigint y(1); + for (; b > 0; b /= 2) { + if (b % 2) y = y * x; + x = x * x; + } + return y; +} + +pair divmod(bigint x, int y) { + if (y < 0) { x.sign = -x.sign; y = -y; } + int rem = 0; + for (int i = x.size()-1; i >= 0; --i) { + x[i] += rem * bigint::B; + rem = x[i] % y; + x[i] /= y; + } + return {x.trim(), rem}; +} +bigint operator/(bigint x, int y) { return divmod(x, y).fst; } +bigint operator%(bigint x, int y) { return divmod(x, y).snd; } + +// Knuth's algorithm D +pair divmod(bigint x, bigint y) { + auto norm = bigint::B / (y.back() + 1); + int qsign = x.sign * y.sign, rsign = x.sign; + x = x * norm; x.sign = +1; + y = y * norm; y.sign = +1; + bigint q, r; + for (int i = (int)x.size()-1; i >= 0; --i) { + r.insert(r.begin(), x[i]); + long long d = ((r.size() > y.size() ? bigint::B * r[y.size()] : 0) + + (r.size()+1 > y.size() ? r[y.size()-1] : 0)) / y.back(); + r = r - y * d; + while (r.sign < 0) { r = r + y; d -= 1; } + q.push_back(d); + } + reverse(all(q)); + q.sign = qsign; r.sign = rsign; + return make_pair(q.trim(), divmod(r.trim(), norm).fst); +} +bigint operator/(bigint x, bigint y) { return divmod(x, y).fst; } +bigint operator%(bigint x, bigint y) { return divmod(x, y).snd; } + + + +int main() { + //cin >> x >> y; + /* + bigint x, y; + cin >> x >> y; + cout << x + y << endl; + */ +} From b9b6e0b7c50600d985b2c0114fb569ee2d3102dc Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 8 Jul 2016 17:28:40 +0900 Subject: [PATCH 056/141] Big Integer --- math/{bigint.cci => bigint.cc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename math/{bigint.cci => bigint.cc} (100%) diff --git a/math/bigint.cci b/math/bigint.cc similarity index 100% rename from math/bigint.cci rename to math/bigint.cc From 427cb0a77cefe5ac24a90556b8d40c93c8772810 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 12 Jul 2016 20:55:09 +0900 Subject: [PATCH 057/141] Maximal Cliques (Bron-Kerbosch) --- graph/maximal_cliques.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/graph/maximal_cliques.cc b/graph/maximal_cliques.cc index 9a9cae8..e45dd36 100644 --- a/graph/maximal_cliques.cc +++ b/graph/maximal_cliques.cc @@ -47,6 +47,7 @@ struct small_graph { // assume: |V| <= 64 N[1ull< rec = [&](state R, state P, state X) { if (!(P | X)) { // R is a bitset of maximal clique for (int i = 0; i < n; ++i, R >>= 1) From 6d97b64b63671811a45140238667266f86d5d229 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 15 Jul 2016 14:19:18 +0900 Subject: [PATCH 058/141] Cube (or Dice) data structure --- other/cube.cc | 56 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/other/cube.cc b/other/cube.cc index 2224399..bd4d10d 100644 --- a/other/cube.cc +++ b/other/cube.cc @@ -1,8 +1,8 @@ // -// Cube data structure +// Cube container // // Descrption: -// A data structure for cube has six faces on +// It has a cube container which has six faces on // front, up, down, left, right, and bottom. // It admits the following three rotations // rotX: front -> up -> back -> down @@ -29,13 +29,57 @@ using namespace std; template struct cube { - T F, U, D, L, R, B; - void rotX() { swap(D, B); swap(B, U); swap(U, F); } // FUBD -> DFUB - void rotY() { swap(D, R); swap(R, U); swap(U, L); } // LURD -> DLUR - void rotZ() { swap(B, R); swap(R, F); swap(F, L); } // LFRB -> BLFR + T F, B, U, D, L, R; + void rotX() { T x = D; D = B; B = U; U = F; F = x; } // FUBD -> DFUB + void rotY() { T x = D; D = R; R = U; U = L; L = x; } // LURD -> DLUR + void rotZ() { T x = B; B = R; R = F; F = L; L = x; } // LFRB -> BLFR + + // usage: + // for (int i = 0; i < 24; ++i) { + // /* do something */ + // c.next_roll(); + // } + // + // or + // + // do { + // /* do something */ + // } while (c.next_roll()); + bool next_roll() { + static int it = 0; + rotZ(); + if (it % 8 == 3) rotX(); + if (it % 8 == 7) rotY(); + return it = (it == 23 ? 0 : it+1); + } + bool operator==(cube c) const { + for (int k = 0; k < 6; ++k) { + if (U != c.U || F != c.F) continue; + for (int i = 0; i < 4; ++i) { + if (L == c.L && F == c.F && R == c.R && L == c.R) return true; + c.rotZ(); + } + if (k % 2) c.rotY(); else c.rotZ(); + } + return false; + } }; +template +ostream &operator<<(ostream &ofs, cube c) { + return (ofs << c.F << c.B << c.U << c.D << c.L << c.R); +} + +void test() { + cube c = {1,2,3,4,5,6}; + do { + cout << c << endl; + } while (c.next_roll()); +} int main() { + test(); + return 0; + int ncase; scanf("%d", &ncase); for (int icase = 0; icase < ncase; ++icase) { cube c; From 81baf29a925b3bb12ea6ae60467ed56357412723 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 30 Aug 2016 19:39:36 +0900 Subject: [PATCH 059/141] Maximum Flow (Edmonds-Karp) --- graph/maximum_flow_edmonds_karp.cc | 60 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/graph/maximum_flow_edmonds_karp.cc b/graph/maximum_flow_edmonds_karp.cc index 450e78a..c5bb619 100644 --- a/graph/maximum_flow_edmonds_karp.cc +++ b/graph/maximum_flow_edmonds_karp.cc @@ -22,8 +22,8 @@ #include #include -#include #include +#include #include #include @@ -33,49 +33,49 @@ using namespace std; #define snd second #define all(c) ((c).begin()), ((c).end()) -const long long INF = (1ll << 50); +const int INF = 1 << 30; struct graph { - typedef long long flow_type; + int n; struct edge { int src, dst; - flow_type capacity, flow; + int capacity, residue; size_t rev; }; - int n; + edge &rev(edge e) { return adj[e.dst][e.rev]; }; + vector> adj; graph(int n) : n(n), adj(n) { } - void add_edge(int src, int dst, flow_type capacity) { + void add_edge(int src, int dst, int capacity) { adj[src].push_back({src, dst, capacity, 0, adj[dst].size()}); adj[dst].push_back({dst, src, 0, 0, adj[src].size()-1}); } int max_flow(int s, int t) { - vector visited(n); - function augment = [&](int u, flow_type cur) { - if (u == t) return cur; - visited[u] = true; - for (auto &e: adj[u]) { - if (!visited[e.dst] && e.capacity > e.flow) { - flow_type f = augment(e.dst, min(e.capacity - e.flow, cur)); - if (f > 0) { - e.flow += f; - adj[e.dst][e.rev].flow -= f; - return f; + for (int u = 0; u < n; ++u) + for (auto &e: adj[u]) e.residue = e.capacity; + int total = 0; + while (1) { + vector prev(n, -1); prev[s] = -2; + queue que; que.push(s); + while (!que.empty() && prev[t] == -1) { + int u = que.front(); que.pop(); + for (edge &e: adj[u]) { + if (prev[e.dst] == -1 && e.residue > 0) { + prev[e.dst] = e.rev; + que.push(e.dst); } } } - return flow_type(0); - }; - for (int u = 0; u < n; ++u) - for (auto &e: adj[u]) e.flow = 0; - - flow_type flow = 0; - while (1) { - fill(all(visited), false); - flow_type f = augment(s, INF); - if (f == 0) break; - flow += f; - } - return flow; + if (prev[t] == -1) break; + int inc = INF; + for (int u = t; u != s; u = adj[u][prev[u]].dst) + inc = min(inc, rev(adj[u][prev[u]]).residue); + for (int u = t; u != s; u = adj[u][prev[u]].dst) { + adj[u][prev[u]].residue += inc; + rev(adj[u][prev[u]]).residue -= inc; + } + total += inc; + } // { u : visited[u] == true } is s-side + return total; } }; From 6c7f256a3315a00bdea9886df068531eebb8c3ec Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 26 Dec 2016 18:51:15 +0900 Subject: [PATCH 060/141] Update README.md --- README.md | 169 ++---------------------------------------------------- 1 file changed, 4 insertions(+), 165 deletions(-) diff --git a/README.md b/README.md index e2760a9..d153897 100644 --- a/README.md +++ b/README.md @@ -7,168 +7,7 @@ These codes are published in **public domain.** You can use the codes for *any purpose without any warranty*. -author: Takanori MAEHARA (e-mail: maehara@prefield.com / twitter: @tmaehara) - - -# List - -## Combinatorics - -- [Next radix number](combinatorics/next_radix.cc) -- [Unique hash for permutations](combinatorics/permutation_hash.cc) -- [Permutation index](combinatorics/permutation_index.cc) -- [Permutation index (general)](combinatorics/permutation_index_general.cc) - - -## Data structure - -- [Zero Suppressed Decision Diagram (ZDD)](data_structure/ZDD.cc) -- [Cartesian Tree](data_structure/cartesian_tree.cc) -- [Fenwick Tree](data_structure/fenwick_tree.cc) -- [2D Fenwick Tree](data_structure/fenwick_tree_2d.cc) -- [Sparse Table](data_structure/sparse_table.cc) -- [Randomized Binary Search Tree](data_structure/randomized_binary_search_tree.cc) -- [Splay Tree](data_structure/splay_tree.cc) -- [Min-Max Heap](data_structure/minmax_heap.cc) -- [Radix Heap](data_structure/radix_heap.cc) -- [Skew Heap](data_structure/skew_heap.cc) -- [Sqrt Array](data_structure/sqrt_array.cc) -- [Union Find](data_structure/union_find.cc) -- [Traversable Union Find](data_structure/union_find2.cc) -- [Wavelet Matrix](data_structure/wavelet_matrix.cc) -- [Persistent array](data_structure/persistent_array.cc) -- [Persistent heap](data_structure/persistent_heap.cc) -- [Persistent rope](data_structure/persistent_rope.cc) -- [Persistent union find](data_structure/persistent_union_find.cc) - - -## Dynamic programming - -This category should be reorganized. - -- dynamic_programming/knapsack.cc -- dynamic_programming/longest_increasing_subsequence.cc -- dynamic_programming/minimum_coin_change.cc -- dynamic_programming/rod_cutting.cc - - -## Computational Geometry (2D) - -- geometry/!circle.cc -- geometry/bk_tree.cc -- geometry/convex_hull.cc -- geometry/covered_range.cc -- geometry/randomized_kd_tree.cc -- geometry/rectangle_union.cc -- geometry/rectilinear_mst.cc -- geometry/vantage_point_tree.cc - - -## Graph Algorithms - -- graph/arborescence.cc -- graph/arborescence2.cc -- graph/articulation_points.cc -- graph/betweenness_centrality.cc -- graph/bipartite_matching.cc -- graph/bipartite_matching_HK.cc -- graph/cycle_enumeration.cc -- graph/dominator_tree.cc -- graph/dynamic_reachability_dag.cc -- graph/euler_tour_tree.cc -- graph/eulerian_path_undirected.cc -- graph/gabow_edmonds.cc -- graph/gomory_hu_tree.cc -- graph/hamilton_cycle_ore.cc -- graph/is_bipartite.cc -- graph/is_chordal.cc -- graph/is_claw_free.cc -- graph/is_cograph.cc -- graph/is_graphic.cc -- graph/isomorphism.cc -- graph/kariv_hakimi.cc -- graph/kcore.cc -- graph/kruskal.cc -- graph/least_common_ancestor_doubling.cc -- graph/least_common_ancestor_heavylight.cc -- graph/least_common_ancestor_sparsetable.cc -- graph/least_common_ancestor_tarjan.cc -- graph/link_cut_tree.cc -- graph/maximal_cliques.cc -- graph/maximum_cut.cc -- [Maximum Flow (Ford-Fulkerson)](graph/maximum_flow_ford_fulkerson.cc) -- [Maximum Flow (Edmonds-Karp)](graph/maximum_flow_edmonds_karp.cc) -- [Maximum Flow (Dinic's blocking flow)](graph/maximum_flow_dinic.cc) -- [Maximum Flow (Goldberg-Tarjan's preflow-push)](graph/maximum_flow_goldberg_tarjan.cc) -- [Minimum Cost Maximum Flow (Tomizawa, Edmonds-Karp's successive shortest paths](graph/minimum_cost_maximum_flow_tomizawa_edmonds_karp_ssp.cc) -- [Minimum Cost Maximum Flow (Goldberg-Tarjan's minimum mean cycle canceling](graph/minimum_cost_maximum_flow_goldberg_tarjan_mmcc.cc) -- graph/minimum_feedback_arc_set.cc -- graph/minimum_mean_cycle.cc -- graph/reachability.cc -- graph/shortest_path_st.cc -- graph/strongly_connected_component_gabow.cc -- graph/strongly_connected_component_kosaraju.cc -- graph/strongly_connected_component_tarjan.cc - -- graph/transitive_reduction_dag.cc -- graph/traveling_salesman.cc -- graph/tree_decomposition.cc -- graph/tree_isomorphism.cc - - -## Mathematics - -This category should be reorganized. - -- math/KaratsubaMultiplication.cc -- math/ODE_dormand_prince.cc -- math/ODE_runge_kutta.cc -- math/SimplexMethodLP.cc -- math/assignment.cc -- math/fast_fourier_transform.cc -- math/fast_modulo_transform.cc -- math/find_min_unimodal.cc -- math/integrate.cc -- math/integrate_DE.cc -- math/linear_recursion.cc -- math/matrix_bool.cc -- math/matrix_double.cc -- math/permanent.cc -- math/polynomial_int.cc -- math/quadratic_equation.cc -- math/satisfiability.cc -- math/satisfiability_hornsat.cc -- math/satisfiability_twosat.cc -- math/zero_one_IP_solver.cc - - -## Number theory - -- number_theory/carmichael_lambda.cc -- number_theory/divisor_sigma.cc -- number_theory/euler_phi.cc -- number_theory/mobius_mu.cc -- number_theory/modular_arithmetics.cc -- number_theory/primes.cc - -## Other - -This category should be reorganized. - -- [Coordinate Compression](other/coordinate_compression.cc) -- [Gregorian Calendar](other/gregorian_calendar.cc) -- [Poker Hands](other/poker_hands.cc) -- [Cube](other/cube.cc) -- other/all_nearest_smaller_values.cc -- other/exact_cover.cc -- other/knapsack_expcore.cc -- other/sorting_network.cc -- other/subset_sum.cc -- other/unweighted_interval_scheduling.cc -- other/weighted_interval_scheduling.cc - - -## Misc -- [Dictionary](_misc/dictionary.cc) -- [Tick](_misc/tick.cc) - +author: Takanori MAEHARA +- e-mail: maehara@prefield.com +- web: http://www.prefield.com +- twitter: @tmaehara From 5fb5e7cf6d4c61fc1aa03db615469e5236161c1a Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 26 Dec 2016 18:51:43 +0900 Subject: [PATCH 061/141] Update README.md --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index d153897..6200a46 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,4 @@ These codes are published in **public domain.** You can use the codes for *any purpose without any warranty*. -author: Takanori MAEHARA -- e-mail: maehara@prefield.com -- web: http://www.prefield.com -- twitter: @tmaehara +author: Takanori MAEHARA (web: http://www.prefield.com, e-mail: maehara@prefield.com, twitter: @tmaehara) From e473ca606d6169255518109777b5de794dc53020 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 29 Dec 2017 10:31:03 +0900 Subject: [PATCH 062/141] Create _geom.cc --- geometry/_geom.cc | 3624 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3624 insertions(+) create mode 100644 geometry/_geom.cc diff --git a/geometry/_geom.cc b/geometry/_geom.cc new file mode 100644 index 0000000..9b4a7a4 --- /dev/null +++ b/geometry/_geom.cc @@ -0,0 +1,3624 @@ +// +// +// http://cs.smith.edu/classwiki/images/c/c8/Mitchell.MinPerim.pdf +// https://www.ics.uci.edu/~eppstein/pubs/EppOveRot-DCG-92.pdf +// https://en.wikipedia.org/wiki/Well-separated_pair_decomposition +// http://www.algorithmic-solutions.info/leda_manual/geo_alg.html +// +// future work: +// boolean operations (polygonal region overlay; 人間には実装無理では) +// ham sandwitch cut https://www.ti.inf.ethz.ch/ew/lehre/CG09/materials/v11.pdf + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(x,a) { auto y=(x); if (sign(y-a)) { cout << "line " << __LINE__ << #x << " = " << y << " != " << a << endl; exit(-1); } } +double urand() { return rand() / (1.0 + RAND_MAX); } + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +template +ostream &operator<<(ostream &os, const vector &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << " "; + os << "]"; + return os; +} +template +ostream &operator<<(ostream &os, const vector> &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << endl << " "; + os << "]"; + return os; +} + +const double PI = acos(-1.0); + +// implementation note: use EPS only in this function +// usage note: check sign(x) < 0, sign(x) > 0, or sign(x) == 0 +const double EPS = 1e-8; +int sign(double x) { + if (x < -EPS) return -1; + if (x > +EPS) return +1; + return 0; +} + +using real = long double; +struct point { + real x, y; + point &operator+=(point p) { x += p.x; y += p.y; return *this; } + point &operator-=(point p) { x -= p.x; y -= p.y; return *this; } + point &operator*=(real a) { x *= a; y *= a; return *this; } + point &operator/=(real a) { return *this *= (1.0/a); } + point operator-() const { return {-x, -y}; } + bool operator<(point p) const { + int s = sign(x - p.x); + return s ? s < 0 : sign(y - p.y) < 0; + } +}; +bool operator==(point p, point q) { return !(p < q) && !(q < p); } +bool operator!=(point p, point q) { return p < q || q < p; } +bool operator<=(point p, point q) { return !(q < p); } +point operator+(point p, point q) { return p += q; } +point operator-(point p, point q) { return p -= q; } +point operator*(real a, point p) { return p *= a; } +point operator*(point p, real a) { return p *= a; } +point operator/(point p, real a) { return p /= a; } +real dot(point p, point q) { return p.x*q.x+p.y*q.y; } +real cross(point p, point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +real norm2(point p) { return dot(p,p); } +point orth(point p) { return {-p.y, p.x}; } +real norm(point p) { return sqrt(dot(p,p)); } +real arg(point p) { return atan2(p.y, p.x); } +real arg(point p, point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const point &p) { os<<"("< 0 && p.y >= 0) return i; + return 0; + } + bool operator()(point p, point q) const { + p = p - o; q = q - o; + if (quad(p) != quad(q)) return s*quad(p) < s*quad(q); + if (cross(p, q)) return s*cross(p, q) > 0; + return norm2(p) < norm2(q); // closer first + } +}; + +struct line { point p, q; }; +bool operator==(line l, line m) { + return !sign(cross(l.p-l.q,m.p-m.q)) && !sign(cross(l.p-l.q,m.p-l.p)); +} + +struct segment { point p, q; }; +bool operator==(segment l, line m) { + return (l.p==m.p && l.q==m.q) || (l.p==m.q && l.q==m.p); // do not consider the direction +} +struct circle { point p; real r; }; +bool operator==(circle c, circle d) { return c.p == d.p && !sign(c.r - d.r); } + +// inner tangent polygon. +// sometimes, circle problem can be reduced to discretized problem +vector discretize(circle c, int n = 50) { + vector ps; + for (int i = 0; i < n; ++i) { + double x = cos(2*PI*i/n), y = sqrt(1 - x*x); + ps.push_back(c.p + c.r * point({x,y})); + } + return ps; +} + +typedef vector polygon; + + +//----------------------------------------------------------------------------- +// visualizer +//----------------------------------------------------------------------------- +struct visualizer { + real minx, maxx, miny, maxy, scale; + ofstream ofs; + visualizer(string s = "data.js") : ofs(s) { + minx = miny = 1.0/0.0; + maxx = maxy = -1.0/0.0; + } + void update(point p) { + minx = min(minx, p.x); miny = min(miny, p.y); + maxx = max(maxx, p.x); maxy = max(maxy, p.y); + scale = 480/(max(maxx-minx, max(maxy-miny,1.0l))); + } + double X(point p) { return scale * (p.x-minx) + 10; } + double Y(point p) { return 490 - scale * (p.y-miny); } + vector ps; + vector ss; + vector cs; + visualizer &operator<<(circle c) { + cs.push_back(c); + update(c.p + point({ c.r, c.r})); + update(c.p + point({-c.r,-c.r})); + return *this; + } + visualizer &operator<<(point p) { + ps.push_back(p); + update(p); + return *this; + } + visualizer &operator<<(segment s) { + ss.push_back(s); + update(s.p); + update(s.q); + return *this; + } + ~visualizer() { + for (point p: ps) + ofs << "circle(" << X(p) << "," << Y(p) << ",3.0)" << endl; + for (segment s: ss) + ofs << "line(" << X(s.p) << "," << Y(s.p) << "," + << X(s.q) << "," << Y(s.q) << ")" << endl; + for (circle c: cs) + ofs << "circle(" << X(c.p) << "," << Y(c.p) << "," << scale*c.r << ")" << endl; + } +}; + + +//----------------------------------------------------------------------------- +// point p is on line l +//----------------------------------------------------------------------------- +vector intersect(line l, point p) { + if (sign(cross(l.p-p, l.q-p)) != 0) return {}; + return {p}; +} +vector intersect(point p, line l) { + return intersect(l, p); +} + +//----------------------------------------------------------------------------- +// point p is on segment s +//----------------------------------------------------------------------------- +vector intersect(segment s, point p) { + if (sign(cross(s.p-p, s.q-p)) != 0) return {}; + if (sign( dot(s.p-p, s.q-p)) > 0) return {}; // > for strict intersect + return {p}; // >= for weak intersect +} +vector intersect(point p, segment s) { + return intersect(s, p); +} + +//----------------------------------------------------------------------------- +// intersection of two lines +// +// Derivation: The crosspoint equation is +// l.p + (l.q - l.p) t == m.p + (m.q - m.p) s ... (CP.1) +// Taking a cross product with (m.q - m.p), we have +// (m.q - m.p) x (l.q - l.p) t == (m.q - m.p) x (m.p - l.p) +// ~~~~~~~~~~~~a~~~~~~~~~~~~ ~~~~~~~~~~~~b~~~~~~~~~~~~ +// +// If a != 0, these two lines have a proper crosspoint. +// If a == 0 and b == 0, these two lines are the same line. +// Otherwise, these two lines are parallel. +//----------------------------------------------------------------------------- +vector intersect(line l, line m) { + auto a = cross(m.q - m.p, l.q - l.p); + auto b = cross(l.p - m.p, l.q - l.p); + if ( sign(a)) return {m.p + b/a*(m.q - m.p)}; // properly crossing + if (!sign(b)) return {m.p, m.q}; // same line + return {}; // disjoint parallel +} + +//----------------------------------------------------------------------------- +// intersection of line and segment +// +// In CP.1, t must be in [0, 1]. Thus 0 <= b/a <= 1 is required. +// By assuming a > 0, it is equivalent to b >= 0 and b-a <= 0 +//----------------------------------------------------------------------------- +vector intersect(line l, segment s) { + auto a = cross(s.q - s.p, l.q - l.p); + auto b = cross(l.p - s.p, l.q - l.p); + if (a < 0) { a *= -1; b *= -1; } + if (sign(b) < 0 || sign(a-b) < 0) return {}; // no intersect + if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing + if (sign(b) == 0) return {s.p, s.q}; // same line + return {}; // disjoint parallel +} + +//----------------------------------------------------------------------------- +// intersection of two segments +// +// Solve two CP.1s simultaneously. +// If two segments are overlapping, it is bit difficult. +//----------------------------------------------------------------------------- +vector intersect(segment s, segment t) { + auto a = cross(s.q - s.p, t.q - t.p); + auto b = cross(t.p - s.p, t.q - t.p); + auto c = cross(s.q - s.p, s.p - t.p); + if (a < 0) { a = -a; b = -b; c = -c; } + if (sign(b) < 0 || sign(a-b) < 0 || + sign(c) < 0 || sign(a-c) < 0) return {}; // disjoint + if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing + vector ps; // same line + auto insert_if_possible = [&](point p) { + for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return; + ps.push_back(p); + }; + if (sign(dot(s.p-t.p, s.q-t.p)) <= 0) insert_if_possible(t.p); + if (sign(dot(s.p-t.q, s.q-t.q)) <= 0) insert_if_possible(t.q); + if (sign(dot(t.p-s.p, t.q-s.p)) <= 0) insert_if_possible(s.p); + if (sign(dot(t.p-s.q, t.q-s.q)) <= 0) insert_if_possible(s.q); + return ps; +} + +//----------------------------------------------------------------------------- +// reflected point with respect to l +//----------------------------------------------------------------------------- +point reflection(point p, line l) { + auto a = dot(l.p-l.q, l.p-l.q); + auto b = dot(l.p-p, l.p-l.q); + return 2 * (l.p + a/b*(l.q - l.p)) - p; +} + +//----------------------------------------------------------------------------- +// closest point on l +//----------------------------------------------------------------------------- +point projection(point p, line l) { + auto a = dot(l.p-l.q, l.p-l.q); + auto b = dot(l.p-p, l.p-l.q); + return l.p + a/b*(l.q - l.p); +} + +//----------------------------------------------------------------------------- +// closest point on s +//----------------------------------------------------------------------------- +point projection(point p, segment s) { + auto a = dot(s.p-s.q, s.p-s.q); + auto b = dot(s.p - p, s.p-s.q); + if (sign(b) < 0) return s.p; + if (sign(a-b) < 0) return s.q; + return s.p + b/a*(s.q - s.p); +} + +//----------------------------------------------------------------------------- +// closest point on c +//----------------------------------------------------------------------------- +point projection(point p, circle c) { + point v = p - c.p; + return c.p + c.r * v / norm(v); +} +//----------------------------------------------------------------------------- +// distances +//----------------------------------------------------------------------------- +real dist(point p, point q) { + return norm(p-q); +} +real dist(point p, line l) { + return dist(p, projection(p, l)); +} +real dist(line l, point p) { + return dist(p, l); +} +real dist(line l, line m) { + if (sign(cross(l.p-l.q,m.p-m.q))) return 0; // cross + return dist(l.p, m); +} +real dist(point p, segment s) { + return dist(p, projection(p, s)); +} +real dist(line l, segment s) { + if (intersect(l, s).size()) return 0; + return min(dist(l, s.p), dist(l, s.q)); +} +real dist(segment s, line l) { + return dist(l, s); +} +real dist(segment s, segment T) { + if (intersect(s, T).size()) return 0; + return min({dist(s.p,T), dist(s.q,T), dist(T.p,s), dist(T.q,s)}); +} + + +//----------------------------------------------------------------------------- +// intersection points of two circles +//----------------------------------------------------------------------------- +vector intersect(circle c, circle d) { + if (c.r < d.r) swap(c, d); + auto pow2 = [](real a) { return a*a; }; + auto g = dot(c.p-d.p, c.p-d.p); + if (sign(g) == 0) { + if (sign(c.r-d.r) != 0) return {}; + return {{c.p.x+c.r, c.p.y}, {c.p.x, c.p.y+c.r}, {c.p.x-c.r, c.p.y}}; + } + int inner = sign(g-pow2(c.r-d.r)); + int outer = sign(g-pow2(c.r+d.r)); + if (inner < 0 || outer > 0) return {}; + if (inner == 0) return {(c.r*d.p-d.r*c.p)/(c.r-d.r)}; + if (outer == 0) return {(c.r*d.p+d.r*c.p)/(c.r+d.r)}; + auto eta = (pow2(c.r) - pow2(d.r) + g)/(2*g); + auto mu = sqrt(pow2(c.r)/g - pow2(eta)); + point q = c.p + eta*(d.p-c.p), v = mu*orth(d.p - c.p); + return {q + v, q - v}; +} + +//----------------------------------------------------------------------------- +// intersection of line and circle +//----------------------------------------------------------------------------- +vector intersect(line l, circle c) { + point u = l.q - l.p, v = l.p - c.p; + auto a = dot(u,u), b = dot(u,v)/a, t = (dot(v,v) - c.r*c.r)/a; + auto det = b*b - t; + if (sign(det) < 0) return {}; // no solution + if (sign(det) == 0) return {l.p - b*u}; // touch inner/outer + return {l.p - (b + sqrt(det))*u, // properly intersect + l.p - (b - sqrt(det))*u}; +} +vector intersect(circle c, line l) { + return intersect(l, c); +} + +//----------------------------------------------------------------------------- +// intersection of segment and circle +// number of points: +// 0 ==> no intersect +// 1 ==> touch +// 2 ==> contained +// 3 ==> penetrating single side +// 4 ==> penetrating both sides +// sorted from s.p to s.q; usually, one would use ans[0] and ans.back(). +//----------------------------------------------------------------------------- +vector intersect(circle c, segment s) { + point u = s.q - s.p, v = s.p - c.p; + auto a = dot(u,u), b = dot(u,v)/a, t = (dot(v,v) - c.r*c.r)/a; + auto det = b*b - t; + if (sign(det) < 0) return {}; // no solution + + auto t1 = -b - sqrt(det), t2 = -b + sqrt(det); + vector ps; + auto insert_if_possible = [&](point p) { + for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return; + ps.push_back(p); + }; + if (sign(c.r - norm(s.p-c.p)) >= 0) insert_if_possible(s.p); + if (sign(t1) >= 0 && sign(1-t1) >= 0) insert_if_possible(s.p+t1*u); + if (sign(t2) >= 0 && sign(1-t2) >= 0) insert_if_possible(s.p+t2*u); + if (sign(c.r - norm(s.q-c.p)) >= 0) insert_if_possible(s.q); + return ps; +} +vector intersect(segment s, circle c) { + return intersect(c, s); +} +bool contains(circle c, point p) { + return sign(dot(c.p-p, c.p-p) - c.r * c.r) <= 0; +} + + +//----------------------------------------------------------------------------- +// polygon contains a point +// half-line crossing method +//----------------------------------------------------------------------------- +int contains(polygon ps, point p) { + bool in = false; + for (int i = 0; i < ps.size(); ++i) { + int j = (i+1 == ps.size() ? 0 : i+1); + point a = ps[i] - p, b = ps[j] - p; + if (a.y > b.y) swap(a, b); + if (a.y <= 0 && 0 < b.y && cross(a, b) < 0) in = !in; + if (!sign(cross(a, b)) && sign(dot(a, b)) <= 0) + return 1; // point on the edge + } + return in ? 2 : 0; // point in:out the polygon +} + +//----------------------------------------------------------------------------- +// convex hull with the given points +// +// Andrew's monotone chain +// +// [verified] +// +// A. M. Andrew (1979): +// Another efficient algorithm for convex hulls in two dimensions. +// Information Processing Letters 9 (5): 216-219. +//----------------------------------------------------------------------------- +polygon convex_hull(vector ps) { + int n = ps.size(), k = 0; + sort(all(ps)); + vector ch(2*n); + auto cond = [&](point p, point q, point o) { + int a = sign(cross(p-o, q-o)); // return a < 0 if no three points on line + return a ? a < 0 : sign(dot(p-o, q-o)) >= 0; + }; + for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull + for (; k >= 2 && cond(ch[k-2], ch[k-1], ps[i]); --k); + for (int i = n-2, t = k+1; i >= 0; ch[k++] = ps[i--]) // upper-hull + for (; k >= t && cond(ch[k-2], ch[k-1], ps[i]); --k); + ch.resize(k-1); + return ch; +} + + +//----------------------------------------------------------------------------- +// farthest pair of points +// +// is located on the convex hull. perform rotating caliper. +// +// [verified ACAC002] +//----------------------------------------------------------------------------- +pair farthest_pair(vector ps) { + vector ch = convex_hull(ps); + int n = ch.size(); + int u = 0, v = 1; + real best = -1; + for (int i = 0, j = 1; i < n; ++i) { + while (1) { + int k = (j+1 < n ? j+1 : 0); + real len = norm2(ch[j] - ch[i]); + if (sign(len - norm2(ch[k] - ch[i])) <= 0) j = k; + else { + if (best < len) { best = len; u = i; v = j; } + break; + } + } + } + return make_pair(ch[u], ch[v]); +} + + +//----------------------------------------------------------------------------- +// signed area of arbitrary polygon +// +// [verified] +//----------------------------------------------------------------------------- +real area(polygon ps) { + if (ps.size() <= 2) return 0; + auto a = cross(ps.back(), ps[0]); + for (int i = 0; i+1 < ps.size(); ++i) + a += cross(ps[i], ps[i+1]); + return a/2; +} + +//----------------------------------------------------------------------------- +// left side of a convex polygon with respect to a line +// +// [verified] +//----------------------------------------------------------------------------- +polygon convex_cut(polygon ps, line l) { + vector qs; + for (int i = 0; i < ps.size(); ++i) { + int j = (i+1 == ps.size() ? 0 : i+1); + if (sign(cross(l.p - ps[i], l.q - ps[i])) >= 0) qs.push_back(ps[i]); + if (sign(cross(l.p - ps[i], l.q - ps[i])) * + sign(cross(l.p - ps[j], l.q - ps[j])) < 0) { + auto a = cross(ps[j] - ps[i], l.q - l.p); + auto b = cross(l.p - ps[i], l.q - l.p); + qs.push_back(ps[i] + b/a*(ps[j] - ps[i])); + } + } + return qs; +} + +//----------------------------------------------------------------------------- +// the circle through three points +//----------------------------------------------------------------------------- +circle three_point_circle(point p, point q, point r) { + point u = orth(q - p), v = r - p; + point o = (p+q + u*dot(r-q,v)/dot(u,v))/2; + return {o, norm(p-o)}; +} +//----------------------------------------------------------------------------- +// area of quadrilateral; +// not verified +//----------------------------------------------------------------------------- +real quadrilateral_area(real a, real b, real c, real d) { + real s = a+b+c+d; + return sqrt((s-a)*(s-b)*(s-c)*(s-d))/4; +} +real triangle_area(real a, real b, real c) { + return quadrilateral_area(a, b, c, 0); +} +real excircle_radius(real a, real b, real c) { + return a*b*c/4/triangle_area(a, b, c); +} +real incircle_radius(real a, real b, real c) { + return 2*triangle_area(a,b,c)/(a+b+c); +} + +//----------------------------------------------------------------------------- +// tangent line of a circle at the nearest point from p +// +// Let q be a tangent point. +// The angle between q -- p -- c.p is +// sin(t) = r/|p - c.p|. +// and the solution is +// p + (c.p - p) * exp(\pm it). +// +// [verified] +//----------------------------------------------------------------------------- +vector tangent(point p, circle c) { + point u = p - c.p, v = orth(u); + auto g = dot(u,u) - c.r*c.r; + if (sign(g) < 0) return {}; + if (sign(g) == 0) return {{p, p + v}}; + u = u * (c.r*c.r/dot(u,u)); + v = v * (c.r*sqrt(g)/dot(v,v)); + return {{p, c.p + u - v}, {p, c.p + u + v}}; +} +vector tangent(circle c, point p) { + return tangent(p, c); +} + +//----------------------------------------------------------------------------- +// common tangents of two circles +// +// [verified] +//----------------------------------------------------------------------------- +vector tangent(circle c, circle d) { + if (c.r < d.r) swap(c, d); + auto g = dot(c.p-d.p, c.p-d.p); + if (sign(g) == 0) return {}; // same origin + point u = (d.p-c.p)/sqrt(g), v = orth(u); // coordinate systems + vector ls; + for (int s = +1; s >= -1; s -= 2) { + auto h = (c.r+s*d.r)/sqrt(g); // = cos(theta) + if (sign(1 - h*h) == 0) { // touch inner/outer + ls.push_back({c.p+c.r*u, c.p+c.r*(u+v)}); + } else if (sign(1 - h*h) > 0) { // properly intersect + point uu = h*u, vv = sqrt(1-h*h)*v; + ls.push_back({c.p+c.r*(uu+vv), d.p-d.r*(uu+vv)*s}); + ls.push_back({c.p+c.r*(uu-vv), d.p-d.r*(uu-vv)*s}); + } + } + return ls; +} + +//----------------------------------------------------------------------------- +// common tangent circles of two lines of radius r +// +// o|o +// --+-- +// o|o +// +// number of solutions: +// 0: parallel and distance < r +// 1: parallel and distance = r +// 4: non-parallel +// +// [non-verified] +//----------------------------------------------------------------------------- +vector tangent_circles(line l, line m, real r) { + vector cs; + real a = cross(l.p-m.p, l.q-l.p), b = cross(m.q-m.p, l.q-l.p); + if (!sign(b)) { // parallel case + if (l.q < l.p) swap(l.p, l.q); + if (m.q < m.p) swap(m.p, m.q); + if (sign(cross(m.p-l.p, m.q-l.p)) >= 0) swap(l, m); // l is lower + point v = orth(m.q - m.p); v /= norm(v); + real d = a / cross(l.q - l.p, v); + if (sign(d - 2*r) == 0) cs.push_back({l.p + r * v, r}); + } else { + point o = m.p + a/b * (m.q - m.p), u = l.q - l.p, v = m.q - m.p; + u /= norm(u); v /= norm(v); + for (int i = 0; i < 4; ++i) { + point w = u + v; w /= norm(w); + real t = r / sqrt(1 - dot(v,w)*dot(v,w)); + cs.push_back({o + t * w, r}); + u *= -1; swap(u, v); + } + } + return cs; +} + +//----------------------------------------------------------------------------- +// find a line that passes the maximum number of points +// +// [non-verified] +//----------------------------------------------------------------------------- +int maximum_points_line(vector ps) { + sort(all(ps)); // assume dx >= 0; if dx == 0 then dy >= 0 + int max_count = 0; + for (int i = 0; i < ps.size(); ++i) { + vector qs; + int base = 1; + for (int j = 0; j < i; ++j) + if (ps[j] == ps[i]) ++base; + else qs.push_back(ps[j] - ps[i]); + sort(all(qs), polar_angle()); + for (int j = 0, k; j < qs.size(); j += k) { + for (k = 1; j+k < qs.size() && sign(cross(qs[j], qs[j+k])) == 0; ++k); + max_count = max(max_count, base + k); + } + } + return max_count; +} + +// for comparison +int maximum_points_line_n(vector ps) { + sort(all(ps)); + int ans = 0; + for (int i = 0; i < ps.size(); ++i) { + for (int j = i+1; j < ps.size(); ++j) { + if (ps[i] == ps[j]) continue; + int count = 0; + for (int k = 0; k < ps.size(); ++k) { + if (intersect((line){ps[i], ps[j]}, ps[k]).size() > 0) ++count; + } + ans = max(ans, count); + } + } + return ans; +} +void verify_maximum_points_line() { + int n = 100; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = rand() % 20; + ps[i].y = rand() % 20; + } + cout << maximum_points_line(ps) << endl; + cout << maximum_points_line_n(ps) << endl; +} + + +//----------------------------------------------------------------------------- +// triangulate simple polygon in O(n) time. +// +// [non-verified]; future work for polygonal overlay +//----------------------------------------------------------------------------- +real triangulate(vector ps) { + int n = ps.size(); + vector next(n); + for (int i = 0; i < n-1; ++i) next[i] = i+1; + auto is_ear = [&](int i, int j, int k) { + if (sign(cross(ps[j]-ps[i], ps[k]-ps[i])) <= 0) return false; + for (int l = next[k]; l != i; l = next[l]) + if (sign(cross(ps[i]-ps[l], ps[j]-ps[l])) >= 0 + && sign(cross(ps[j]-ps[l], ps[k]-ps[l])) >= 0 + && sign(cross(ps[k]-ps[l], ps[i]-ps[l])) >= 0) return false; + return true; + }; + real area = 0; + for (int i = 0; next[next[i]] != i; ) { + if (is_ear(i, next[i], next[next[i]])) { + area += abs(cross(ps[next[i]]-ps[i], ps[next[next[i]]] - ps[i])) / 2; + next[i] = next[next[i]]; + } else i = next[i]; + } + return area; +} + +//----------------------------------------------------------------------------- +// area of intersection of two circles +// [verified] +//----------------------------------------------------------------------------- +real intersection_area(circle c, circle d) { + if (c.r < d.r) swap(c, d); + auto A = [&](real r, real h) { + return r*r*acos(h/r)-h*sqrt(r*r-h*h); + }; + auto l = norm(c.p - d.p), a = (l*l + c.r*c.r - d.r*d.r)/(2*l); + if (sign(l - c.r - d.r) >= 0) return 0; // far away + if (sign(l - c.r + d.r) <= 0) return PI*d.r*d.r; + if (sign(l - c.r) >= 0) return A(c.r, a) + A(d.r, l-a); + else return A(c.r, a) + PI*d.r*d.r - A(d.r, a-l); +} +//----------------------------------------------------------------------------- +// circle-polygon intersection area +// [verified] +//----------------------------------------------------------------------------- +real intersection_area(vector ps, circle c) { + auto tri = [&](point p, point q){ + point d = q - p; + auto a = dot(d,p)/dot(d,d), b = (dot(p,p)-c.r*c.r)/dot(d,d); + auto det = a*a - b; + if (det <= 0) return arg(p,q) * c.r*c.r / 2; + auto s = max(0.l, -a-sqrt(det)), t = min(1.l, -a+sqrt(det)); + if (t < 0 || 1 <= s) return c.r*c.r*arg(p,q)/2; + point u = p + s*d, v = p + t*d; + return arg(p,u)*c.r*c.r/2 + cross(u,v)/2 + arg(v,q)*c.r*c.r/2; + }; + auto sum = 0.0; + for (int i = 0; i < ps.size(); ++i) + sum += tri(ps[i] - c.p, ps[(i+1)%ps.size()] - c.p); + return sum; +} +real intersection_area(circle c, vector ps) { + return intersection_area(ps, c); +} + +//----------------------------------------------------------------------------- +// find the closest pair of points by sweepline +// [verified] +//----------------------------------------------------------------------------- +pair closest_pair(vector ps) { + sort(all(ps), [](point p, point q) { return p.y < q.y; }); + auto u = ps[0], v = ps[1]; + auto best = dot(u-v, u-v); + auto update = [&](point p, point q) { + auto dist = dot(p-q, p-q); + if (best > dist) { best = dist; u = p; v = q; } + }; + set S; S.insert(u); S.insert(v); + for (int l = 0, r = 2; r < ps.size(); ++r) { + if (S.count(ps[r])) return {ps[r], ps[r]}; + if ((ps[l].y-ps[r].y)*(ps[l].y-ps[r].y) > best) S.erase(ps[l++]); + auto i = S.insert(ps[r]).fst; + for (auto j = i; ; ++j) { + if (j == S.end() || (i->x-j->x)*(i->x-j->x) > best) break; + if (i != j) update(*i, *j); + } + for (auto j = i; ; --j) { + if (i != j) update(*i, *j); + if (j == S.begin() || (i->x-j->x)*(i->x-j->x) > best) break; + } + } + return {u, v}; +} +//----------------------------------------------------------------------------- +// find the closest pair of points by divide and conquer +// (slower than the sweepline) +//----------------------------------------------------------------------------- +pair closest_pair2(vector ps) { + sort(all(ps), [](point p, point q) { return p.y < q.y; }); + auto u = ps[0], v = ps[1]; + auto best = dot(u-v, u-v); + auto update = [&](point p, point q) { + auto dist = dot(p-q, p-q); + if (best > dist) { best = dist; u = p; v = q; } + }; + function rec = [&](int l, int r) { + if (r - l <= 1) { + for (int i = l; i < r; ++i) + for (int j = i+1; j < r; ++j) + update(ps[i], ps[j]); + stable_sort(&ps[l], &ps[r]); + } else { + int m = (l + r) / 2; + auto y = ps[m].y; + rec(l, m); rec(m, r); + inplace_merge(&ps[l], &ps[m], &ps[r]); + vector qs; + for (int i = l; i < r; ++i) { + if ((ps[i].y-y)*(ps[i].y-y) >= best) continue; + for (int j = (int)qs.size()-1; j >= 0; --j) { + if ((qs[j].x-ps[i].x)*(qs[j].x-ps[i].x) >= best) break; + update(qs[j], ps[i]); + } + qs.push_back(ps[i]); + } + } + }; + rec(0, ps.size()); + return {u, v}; +} + + +//----------------------------------------------------------------------------- +// half-plane intersection in O(n log n) +// [un-verified; buggy?] +//----------------------------------------------------------------------------- +vector half_plane_intersection(vector ls) { + int n = ls.size(); + sort(all(ls), [&](line l, line m) { return arg(l.p-l.q) < arg(m.p-m.q); }); + int L = 0, R = 0; + vector bd(2*n); + vector ps(2*n); + bd[R] = ls[0]; + auto left = [&](point p, line l) { return sign(cross(l.p-p, l.q-p)) >= 0; }; + for (int i = 1; i < n; ++i) { + if (!sign(cross(bd[R].p-bd[R].q, ls[i].p-ls[i].q))) { + if (left(ls[i].p, bd[R])) bd[R] = ls[i]; + } else { + while (L < R && !left(ps[R-1], ls[i])) --R; + while (L < R && !left(ps[L] , ls[i])) ++L; + bd[++R] = ls[i]; + } + if (R > L) ps[R-1] = intersect(bd[R-1], bd[R])[0]; + } + while (L < R && !left(ps[R-1], bd[L])) --R; + if (R - L <= 1) return {}; + if (R > L) ps[R] = intersect(bd[L], bd[R])[0]; + vector ch = {ps[L]}; + for (int i = L+1; i <= R; ++i) + if (!(ch.back() == ps[i])) ch.push_back(ps[i]); + if (ch.size() > 1 && ch.back() == ch[0]) ch.pop_back(); + return ch; +} + + + +//----------------------------------------------------------------------------- +// geometric median, i.e., p in argmin sum |ps[i] - p|_2 +// +// Weiszfield's iterative reweighted method least squares +// with avoiding equal points +// [verified: LA5102] +//----------------------------------------------------------------------------- +point geometric_median(vector ps) { + point g = {0,0}; + real eta = 1000.0; + for (int iter = 0; iter < 1000000; ++iter, eta /= 2) { + real w = 0; + point h = {0,0}; + for (point p: ps) { + real a = eta + norm(p - g); + h = h + p/a; w = w + 1/a; + } + h = h / w; swap(g, h); + if (norm(g - h) < EPS) break; + } + return g; +} + + +//----------------------------------------------------------------------------- +// find a circle of radius r that contains many points as possible +// +// quad-tree search (this is faster than the next sweepline solution) +// [verified: AOJ 1132] +//----------------------------------------------------------------------------- +int maximum_circle_cover(vector ps, double r) { + const double dx[] = {1,-1,-1,1}, dy[] = {1,1,-1,-1}; + point best_p; + int best = 0; + function)> + rec = [&](point p, double w, vector ps) { + w /= 2; + point qs[4]; + vector pss[4]; + for (int i = 0; i < 4; ++i) { + qs[i] = p + w * point({dx[i], dy[i]}); + int lo = 0; + for (point q: ps) { + auto d = dist(qs[i], q); + if (sign(d - r) <= 0) ++lo; + if (sign(d - w*sqrt(2) - r) <= 0) pss[i].push_back(q); + } + if (lo > best) { best = lo; best_p = qs[i]; } + } + for (int i = 0, j; i < 4; ++i) { + for (int j = i+1; j < 4; ++j) + if (pss[i].size() < pss[j].size()) + swap(pss[i], pss[j]), swap(qs[i], qs[j]); + if (pss[i].size() <= best) break; + rec(qs[i], w, pss[i]); + } + }; + real w = 0; + for (point p: ps) w = max(w, max(abs(p.x), abs(p.y))); + rec({0,0}, w, ps); + return best; //best_p; +} + +//----------------------------------------------------------------------------- +// find a circle of radius r that contains many points as possible +// +// sweepline O(n^2 log n). +// [verified: AOJ 1132] +//----------------------------------------------------------------------------- +int maximum_circle_cover2(vector ps, double r) { + int best = 0; + for (point p: ps) { + int count = 0; + vector> aux; + for (point q: ps) { + auto d = dist(p, q); + if (sign(d) == 0) ++count; + else if (sign(d - 2*r) <= 0) { + auto theta = arg(q-p); + auto phi = acos(min(1.l, d/(2*r))); + aux.push_back({theta-phi, -1}); + aux.push_back({theta+phi, +1}); + } + } + sort(all(aux)); + best = max(best, count); + for (auto a: aux) + best = max(best, count -= a.snd); + } + return best; +} + +//----------------------------------------------------------------------------- +// area of union of rectangles +// Bentley's sweepline with segment tree. +// +// [accepted, LightOJ 1120 Rectangle Union] +//----------------------------------------------------------------------------- +struct rectangle { point p, q; }; // lower-left and upper-right +real rectangle_union(vector rs) { + vector ys; // plane sweep with coordinate compression + struct event { + real x, ymin, ymax; + int add; + bool operator<(event e) const { return x < e.x; } + }; + vector es; + for (auto r: rs) { + ys.push_back(r.p.y); + ys.push_back(r.q.y); + es.push_back({r.p.x, r.p.y, r.q.y, +1}); + es.push_back({r.q.x, r.p.y, r.q.y, -1}); + } + sort(all(es)); + sort(all(ys)); + ys.erase(unique(all(ys)), ys.end()); + + vector len(4 * ys.size()); // segment tree on sweepline + vector sum(4 * ys.size()); + function update + = [&](real ymin, real ymax, int add, int i, int j, int k) { + ymin = max(ymin, ys[i]); ymax = min(ymax, ys[j]); + if (ymin >= ymax) return; + if (ys[i] == ymin && ys[j] == ymax) sum[k] += add; + else { + update(ymin, ymax, add, i, (i+j)/2, 2*k+1); + update(ymin, ymax, add, (i+j)/2, j, 2*k+2); + } + if (sum[k]) len[k] = ys[j] - ys[i]; + else len[k] = len[2*k+1] + len[2*k+2]; + }; + real area = 0; + for (int i = 0; i+1 < es.size(); ++i) { + update(es[i].ymin, es[i].ymax, es[i].add, 0, ys.size()-1, 0); + area += len[0] * (es[i+1].x - es[i].x); + } + return area; +} + +//----------------------------------------------------------------------------- +// number of points below ps[i]--ps[j] +// +// TODO: めっちゃバグる・バグってるなう +// +// [non-verified] +//----------------------------------------------------------------------------- +struct points_counter { + int n; + vector ps; + vector> low; // low[i][j] is the number of points below (ps[i], ps[j]) + points_counter(vector ps_) : n(ps_.size()), ps(ps_), low(n, vector(n)) { + double sint = 1e-1, cost = sqrt(1 - sint*sint); // perturbation + for (point &p: ps) p = {p.x*cost - p.y*sint, p.x*sint + p.y*cost}; + + vector is(n); iota(all(is), 0); + sort(all(is), [&](int i, int j) { return ps[i] < ps[j]; }); + + vector left; + vector> iss(n); // iss[i] = points smaller than i, sorted by the polar angle + for (int o: is) { + sort(all(left), [&](int j, int k) { // sort in clock-wise order + point u = ps[j] - ps[o], v = ps[k] - ps[o]; + int s = sign(cross(u, v)); + return s ? s < 0 : dot(u,u) > dot(v,v); + }); + iss[o] = left; + left.push_back(o); + } + for (int o: is) { + cout << "processing " << ps[o] << endl; + cout << iss[o].size() << endl; + for (int i = 0; i+1 < iss[o].size(); ++i) { + int a = iss[o][i], b = iss[o][i+1]; + cout << " comparing " << ps[a] << " " << ps[b] << endl; + if (ps[b] < ps[a]) low[b][o] = low[a][o] + low[a][b] + 1; + else low[b][o] = low[a][o] - low[a][b]; + low[o][b] = low[b][o]; + } + } + cout << low << endl; + + + vector> low2(n, vector(n)); + for (int i = 0; i < n; ++i) { + for (int j = i+1; j < n; ++j) { + for (int k = 0; k < n; ++k) { + if (k == i || k == j) continue; + point p = ps[i], q = ps[j], r = ps[k]; + if (q < p) swap(p, q); // assume p < q + if (r.x < p.x || r.x >= q.x) continue; + if (sign(cross(q-r, p-r)) > 0) low2[i][j]++; + } + low2[j][i] = low2[i][j]; + } + } + cout << low2 << endl; + } + int count(int a, int b, int o) { // i -> j -> k ccw order + if (ps[b] < ps[a]) swap(a, b); + if (ps[o] < ps[b]) swap(b, o); + if (ps[b] < ps[a]) swap(a, b); + if (ps[b].y < ps[a].y) swap(a, b); + cout << "comparing " << ps[a] << " " << ps[b] << " " << ps[o] << endl; + cout << "values " << low[o][a] << " " << low[a][b] << " " << low[o][b] << endl; + return low[o][a] + low[a][b] - low[o][b] + (ps[a].x > ps[b].x); + } +}; + + +//----------------------------------------------------------------------------- +// segment arrangement +// +// graph whose vertices are the points and edges are the segments. +// complexity is O(m^2 log m). +// +// [accepted: AOJ 1226] +// [accepted: AOJ 2068] +// [accepted: AOJ 0273] +//----------------------------------------------------------------------------- +namespace arrangement_slow { +struct arrangement { + struct edge { + int src, dst; + real weight; + size_t id, rev; + }; + int n; + vector ps; + map id; + vector> adj; + + arrangement(vector ss) : n(0) { + vector>> group(ss.size()); + auto append = [&](int i, point p) { + if (!id.count(p)) { id[p] = n++; ps.push_back(p); } + group[i].push_back({norm(ss[i].p - p), id[p]}); + }; + for (int i = 0; i < ss.size(); ++i) { + append(i, ss[i].p); append(i, ss[i].q); + for (int j = 0; j < i; ++j) { + for (point p: intersect(ss[i], ss[j])) { + append(i, p); append(j, p); + } + } + } + adj.resize(n); + for (auto &vs: group) { + sort(all(vs)); + for (int i = 0; i+1 < vs.size(); ++i) { + auto u = vs[i].snd, v = vs[i+1].snd; + if (u == v) continue; + auto len = vs[i+1].fst - vs[i].fst; + adj[u].push_back({u, v, len}); + adj[v].push_back({v, u, len}); + } + } + // remove duplicates and orient edges + vector> idx(n); + for (int u = 0; u < n; ++u) { + auto eq = [&](edge e, edge f) { return e.dst == f.dst; }; + auto lt = [&](edge e, edge f) { return e.dst < f.dst; }; + sort(all(adj[u]), lt); + adj[u].erase(unique(all(adj[u]), eq), adj[u].end()); + sort(all(adj[u]), [&](edge e, edge f) { + return arg(ps[e.dst] - ps[e.src]) > arg(ps[f.dst] - ps[f.src]); + }); + for (int i = 0; i < adj[u].size(); ++i) { + adj[u][i].id = i; + int v = adj[u][i].dst; + idx[u][v] = i; + if (idx[v].count(u)) { + int j = idx[v][u]; + adj[u][i].rev = j; + adj[v][j].rev = i; + } + } + } + } + // traverse utilities for DCEL (planar graph) + // traversing edges surrounding the left face + edge twin(edge e) const { return adj[e.dst][e.rev]; } + edge next(edge e) const { + int j = adj[e.dst][e.rev].id + 1; + if (j >= adj[e.dst].size()) j = 0; + return adj[e.dst][j]; + } + edge outer() const { + int s = 0; // leftmost, outerface edge + for (int i = 1; i < n; ++i) if (ps[i] < ps[s]) s = i; + for (int i = 0; i < adj[s].size(); ++i) { + edge e1 = adj[s][i], e2 = adj[s][(i+1)%adj[s].size()]; + if (cross(ps[e1.dst]-ps[s], ps[e2.dst]-ps[s]) <= 0) return e1; + } + } + + // [accepted: AOJ 2068 Hide-and-Seek] + void shortest_path(point sp) { + int s = id[sp]; + vector dist(n, 1.0/0.0); + vector prev(n, -1); + typedef pair node; + priority_queue, greater> Q; + Q.push(node(dist[s] = 0, s)); + while (!Q.empty()) { + node z = Q.top(); Q.pop(); + if (dist[z.snd] <= z.fst) { + for (auto e: adj[z.snd]) { + if (dist[e.dst] > dist[e.src] + e.weight) { + dist[e.dst] = dist[e.src] + e.weight; + prev[e.dst] = e.src; + Q.push({dist[e.dst], e.dst}); + } + } + } + } + real ans = 0; + for (int u = 0; u < n; ++u) { + for (edge e: adj[u]) { + real s = (dist[e.dst] - dist[e.src] + e.weight)/2; + ans = max(ans, dist[e.src] + s); + } + } + printf("%.12lf\n", ans); + } + + // [accepted: AOJ 1226 Fishnet] + template + void traverse(edge e, F func) { + edge s = e; + do { + func(e); + e = next(e); + } while (e.src != s.src || e.dst != s.dst); + } + void traverse_all_faces() { + vector> visited(n); + real ans = 0; + for (int u = 0; u < n; ++u) { + for (edge e: adj[u]) { + if (!visited[e.src].count(e.dst)) { + real area = 0; + traverse(e, [&](edge e) { + visited[e.src].insert(e.dst); + area += cross(ps[e.src], ps[e.dst]); + }); + ans = max(ans, area); + } + } + } + printf("%.6f\n", ans/2); + } + void traverse_all_faces2() { + vector> visited(n); + real ans = 0; + for (int u = 0; u < n; ++u) { + for (edge e: adj[u]) { + if (!visited[e.src].count(e.dst)) { + real area = 0; + traverse(e, [&](edge e) { + visited[e.src].insert(e.dst); + area += cross(ps[e.src], ps[e.dst]); + }); + if (area > 0) ans += area; + } + } + } + printf("%.12f\n", ans/2); + } + edge contains() { + vector> visited(n); + auto contains = [&](edge e, point p) { + edge s = e; + bool in = false; + do { + point a = ps[e.src] - p, b = ps[e.dst] - p; + if (a.y > b.y) swap(a, b); + if (a.y <= 0 && 0 < b.y && cross(a, b) < 0) in = !in; + if (!sign(cross(a, b)) && sign(dot(a, b)) <= 0) + return 1; // point on the edge + visited[e.src].count(e.dst); + e = next(e); + } while (e.src != s.src || e.dst != s.dst); + return in ? 2 : 0; // point in:out the polygon + }; + for (int u = 0; u < n; ++u) + for (edge e: adj[u]) + if (!visited[e.src].count(e.dst)) + if (contains(e, (point){0,0})) return e; + return {-1}; + } +}; + +void AOJ0273() { + for (int c, w; ~scanf("%d %d", &c, &w) && c; ) { + vector ps(c); + for (int i = 0; i < c; ++i) { + scanf("%lf %lf", &ps[i].x, &ps[i].y); + } + vector ss; + for (int i = 0; i < w; ++i) { + int u, v; scanf("%d %d", &u, &v); + ss.push_back({ps[u-1], ps[v-1]}); + } + arrangement arr(ss); + typedef arrangement::edge edge; + edge e = arr.outer(); // outer-face edge + + vector> step(arr.n); + queue que; + auto proceed = [&](edge s, int value) { + if (step[s.src].count(s.dst)) return; + edge e = s; + do { + step[e.src][e.dst] = value; + que.push(arr.twin(e)); + e = arr.next(e); + } while (e.src != s.src || e.dst != s.dst); + }; + proceed(e, 0); + int ans = 0; + while (!que.empty()) { + edge e = que.front(); que.pop(); + ans = step[e.dst][e.src]; + proceed(e, ans + 1); + } + printf("%d\n", ans); + } +} + + + +void AOJ1226() { + for (int n; ~scanf("%d", &n) && n; ) { + vector> a(4, vector(n)); + for (int k = 0; k < 4; ++k) + for (int i = 0; i < n; ++i) + scanf("%lf", &a[k][i]); + + vector ss = { + {{0,0},{0,1}}, + {{0,1},{1,1}}, + {{1,1},{1,0}}, + {{1,0},{0,0}} + }; + for (int i = 0; i < n; ++i) { + ss.push_back({{a[0][i],0},{a[1][i],1}}); + ss.push_back({{0,a[2][i]},{1,a[3][i]}}); + } + arrangement arr(ss); + arr.traverse_all_faces(); + } +} + +void AOJ2448() { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + vector ss; + for (int i = 0; i+1 < n; ++i) + ss.push_back({ps[i], ps[i+1]}); + arrangement arr(ss); + arr.traverse_all_faces2(); +} + +void AOJ1247() { + for (int n; ~scanf("%d", &n) && n; ) { + vector ss; + for (int i = 0; i < n; ++i) { + double x1, y1, x2, y2; + scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2); + ss.push_back({{x1,y1},{x2,y2}}); + } + arrangement arr(ss); + if (arr.contains().src >= 0) printf("yes\n"); + else printf("no\n"); + } +} +} +// --------------------------------------------------------------------------- +// segment arrangement (Bentley-Ottman's plane sweep) +// +// graph whose vertices are the points and edges are the segments. +// complexity is O((n + k) log n); where k is the number of intersections. +// +// Verified: AOJ1226, AOJ2448 +// --------------------------------------------------------------------------- +struct arrangement { + struct Vertex; struct Edge; // Doubly Connected Edge List + struct Vertex { + point p; // + Edge *edge; // any edge incident to this vertex + }; + struct Edge { + Vertex *vertex; // origin vertex of the edge + Edge *twin; // reverse edge of e + Edge *prev, *next; // surrounding edges of face (CCW) + }; + map> adj; + vector vertices; + vector edges; + + vector segs; + + struct node { // Sweep-Line Structure (RBST) + int index; + int size = 1; + node *left = 0, *right = 0; + } *root = 0; + vector ns; + + node *update(node *x) { + if (x) { + x->size = 1; + if (x->left) x->size += x->left->size; + if (x->right) x->size += x->right->size; + } + return x; + } + node *merge(node *x, node *y) { + if (!x) return y; + if (!y) return x; + if (rand() % (x->size + y->size) < x->size) { + x->right = merge(x->right, y); + return update(x); + } else { + y->left = merge(x, y->left); + return update(y); + } + } + template // 3-way split: cond(x) < 0, cond(x) == 0, cond(x) > 0 + tuple split(node *x, C cond) { + if (!x) return make_tuple(x,x,x); + if (cond(x) == 0) { + auto a = split(x->left, cond); + auto b = split(x->right, cond); + x->left = x->right = 0; update(x); + get<1>(a) = merge(merge(get<1>(a), x), get<1>(b)); + get<2>(a) = get<2>(b); + return a; + } + if (cond(x) < 0) { + auto a = split(x->right, cond); + x->right = 0; update(x); + get<0>(a) = merge(x, get<0>(a)); + return a; + } + if (cond(x) > 0) { + auto a = split(x->left, cond); + x->left = 0; update(x); + get<2>(a) = merge(get<2>(a), x); + return a; + } + } + node *leftmost(node *x) { while (x && x->left) x = x->left; return x; } + node *rightmost(node *x) { while (x && x->right) x = x->right; return x; } + template + void process(node *x, F func) { + if (!x) return; + process(x->left, func); + func(x); + process(x->right, func); + } + + arrangement(vector segs_) : segs(segs_) { + ns.resize(segs.size()); + + set events; + map> L, R; + for (int i = 0; i < segs.size(); ++i) { + if (segs[i].q < segs[i].p) swap(segs[i].p, segs[i].q); + events.insert(segs[i].p); + events.insert(segs[i].q); + L[segs[i].p].insert(i); + R[segs[i].q].insert(i); + ns[i].index = i; + } + vector last(segs.size()); + + while (!events.empty()) { + const point p = *events.begin(); + events.erase(events.begin()); + + Vertex *u = new Vertex({p}); + vertices.push_back(u); + + auto cond = [&](node *x) { + const segment &s = segs[x->index]; + if (sign(s.q.x - s.p.x) == 0) { + if (sign(p.y - s.p.y) < 0) return -1; + if (sign(s.q.y - p.y) < 0) return +1; + return 0; + } + return -sign(cross(s.p - p, s.q - p)); + }; + auto z = split(root, cond); + vector inserter; + process(get<1>(z), [&](node *x) { + Vertex *v = last[x->index]; + if (!adj[u][v]) { + adj[u][v] = new Edge({u}); + adj[v][u] = new Edge({v}); + adj[u][v]->twin = adj[v][u]; + adj[v][u]->twin = adj[u][v]; + edges.push_back(adj[u][v]); + edges.push_back(adj[v][u]); + } + if (!R[p].count(x->index)) + inserter.push_back(x); + }); + for (int i: L[p]) + if (!R[p].count(i)) + inserter.push_back(&ns[i]); + + sort(all(inserter), [&](node *x, node *y) { + const segment &s = segs[x->index], &t = segs[y->index]; + return sign(cross(s.q - s.p, t.q - t.p)) >= 0; + }); + auto add_event = [&](node *x, node *y) { + if (!x || !y) return; + vector ps = intersect(segs[x->index], segs[y->index]); + for (point q: ps) + if (p < q) events.insert(q); + }; + if (inserter.empty()) { + add_event(rightmost(get<0>(z)), leftmost(get<2>(z))); + } else { + add_event(rightmost(get<0>(z)), inserter[0]); + add_event(leftmost(get<2>(z)), inserter.back()); + } + root = 0; + for (int i = 0; i < inserter.size(); ++i) { + last[inserter[i]->index] = u; + inserter[i]->left = inserter[i]->right = 0; + root = merge(root, update(inserter[i])); + } + root = merge(merge(get<0>(z), root), get<2>(z)); + } + for (auto &pp: adj) { + Vertex *u = pp.fst; + vector es; + for (auto z: pp.snd) es.push_back(z.snd); + sort(all(es), [&](Edge *e, Edge *f) { + auto quad = [](point p) { + for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y)) + if (p.x > 0 && p.y >= 0) return i; + return 0; + }; + const point p = e->twin->vertex->p - e->vertex->p; + const point q = f->twin->vertex->p - f->vertex->p; + if (quad(p) != quad(q)) return quad(p) < quad(q); + return sign(cross(p, q)) > 0; + }); + u->edge = es.back(); + for (Edge *e: es) { + u->edge->next = e; + u->edge->next->prev = u->edge; + u->edge = u->edge->next; + } + } + } +}; +void AOJ1226() { + for (int n; ~scanf("%d", &n) && n; ) { + //cout << n << endl; + vector> a(4, vector(n)); + for (int k = 0; k < 4; ++k) + for (int i = 0; i < n; ++i) + scanf("%lf", &a[k][i]); + + vector ss = { + {{0,0},{0,1}}, + {{0,1},{1,1}}, + {{1,1},{1,0}}, + {{1,0},{0,0}} + }; + for (int i = 0; i < n; ++i) { + ss.push_back({{a[0][i],0},{a[1][i],1}}); + ss.push_back({{0,a[2][i]},{1,a[3][i]}}); + } + arrangement arr(ss); + + double result = 0; + set seen; + for (auto *e: arr.edges) { + if (seen.count(e)) continue; + auto *f = e; + double area = 0; + do { + seen.insert(f); + area += cross(f->vertex->p, f->twin->vertex->p); + f = f->twin->prev; + } while (f != e); + result = max(result, area); + } + printf("%.6f\n", result/2); + } +} +void AOJ2448() { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + vector ss; + for (int i = 0; i+1 < n; ++i) + ss.push_back({ps[i], ps[i+1]}); + arrangement arr(ss); + + double result = 0; + set seen; + for (auto *e: arr.edges) { + if (seen.count(e)) continue; + auto *f = e; + double area = 0; + do { + seen.insert(f); + area += cross(f->vertex->p, f->twin->vertex->p); + f = f->twin->prev; + } while (f != e); + if (area > 0) result += area; + } + printf("%.12f\n", result/2); +} + + +//----------------------------------------------------------------------------- +// visibility graph in O(|points|^2 |obstacles|) +// +// Here, the visibility of p and q is: +// 1. p, q in [a,b] ==> visible +// 2. a in (p,q) ==> invisible +// 3. (p,q) intersects (a,b) ==> invisible +// 4. m=(p+q)/2 in int(obs) ==> invisible +// +// [non-verified]; +//----------------------------------------------------------------------------- +struct visibility_graph { + struct edge { + int src, dst; + real weight; + }; + int n; + vector ps; + vector> adj; + visibility_graph(vector ps, vector os) : + n(ps.size()), ps(ps), adj(n) { + auto blocked = [&](point s, point t, polygon &obs) { + bool in = false, on = false; + point m = (s + t) / 2; + for (int i = 0; i < obs.size(); ++i) { + int j = (i+1 == obs.size() ? 0 : i+1); + point a = obs[i], b = obs[j]; + if (!sign(cross(a-s,b-s)) && sign(dot(a-s,b-s)) <= 0 && // s is on [a,b] and t is on [a,b] + !sign(cross(a-t,b-t)) && sign(dot(a-t,b-t)) <= 0) return false; + if (!sign(cross(s-a,t-a)) && sign(dot(s-a,t-a)) < 0) return false; // (s,t) contains a + if (sign(cross(a-s,b-s))*sign(cross(a-t,b-t)) < 0 && // (s,t) intersects (a,b) + sign(cross(s-a,t-a))*sign(cross(s-b,t-b)) < 0) return true; + if (b.y < a.y) swap(a, b); // a is lower + if (a.y <= m.y && m.y < b.y) + if (sign(cross(a-m, b-m)) < 0) in = !in; + } + return in; // midpoint is on obs + }; + for (int i = 0; i < ps.size(); ++i) { + for (int j = i+1, k; j < ps.size(); ++j) { + for (k = 0; k < os.size(); ++k) + if (blocked(ps[i], ps[j], os[k])) break; + if (k == os.size()) { + auto len = norm(ps[i] - ps[j]); + adj[i].push_back({i, j, len}); + adj[j].push_back({j, i, len}); + } + } + } + } +}; +// +// weighted geometric shortest path +// +// find a shortest path on 2D plane, +// where each obstacle is assigned a weight (inverse velocity). +// if weight = INF, it reduced to the standard geometric shortest path problem. +// +// basic algorithm: A* search on implicit visibility graph. +// It performs O(n^2) A* search with dist(u,t) as a heuristics. +// +// on a weighted problem, divide edges to approximate solutions. +// +// reference: +// L. Aleksandrov, A. Maheshwari, and J. -R. Sack (1998): +// Determining approximate shortest paths on weighted polyhedral surfaces. +// +// see aso: http://arxiv.org/pdf/0904.2550.pdf +// +struct geometric_shortest_path { + vector ps; + vector prev, next; + vector> region; + vector weight; + void add_region(vector poly, real w = 1.0/0.0) { + int n = ps.size(), k = poly.size(); + vector obj; + for (int i = 0; i < k; ++i) { + ps.push_back(poly[i]); + obj.push_back(n+i); + next.push_back(n+i+1); + prev.push_back(n+i-1); + } + next[n+k-1] = n; + prev[n] = n+k-1; + region.push_back(obj); + weight.push_back(w); + } + void refine(int v) { + auto divide = [&](int u, int w) { + int v = ps.size(); + ps.push_back((ps[u] + ps[w])/2); + prev.push_back(u); + next.push_back(w); + prev[next[v]] = v; + next[prev[v]] = v; + }; + divide(prev[v], v); + divide(v, next[v]); + } + enum { INTERSECT, CONTAINED, ONLINE, VISIBLE }; + int visibility(point s, point t, vector ®) { + bool in = false; + point m = (s + t) / 2; + for (int i = 0; i < reg.size(); ++i) { + point a = ps[reg[i]], b = ps[reg[(i+1)%reg.size()]]; + if (!sign(cross(a-s,b-s)) && sign(dot(a-s,b-s)) <= 0 && // s is on [a,b] and t is on [a,b] + !sign(cross(a-t,b-t)) && sign(dot(a-t,b-t)) <= 0) return ONLINE; + if (sign(cross(a-s,b-s))*sign(cross(a-t,b-t)) < 0 && // (s,t) intersects (a,b) + sign(cross(s-a,t-a))*sign(cross(s-b,t-b)) < 0) return INTERSECT; + if (b.y < a.y) swap(a, b); + if (a.y <= m.y && m.y < b.y && sign(cross(a-m, b-m)) < 0) in = !in; + } + return in ? CONTAINED : VISIBLE; + } + real length(int u, int v) { + point s = ps[u], t = ps[v]; + auto len = norm(s - t); + for (int i = 0; i < region.size(); ++i) { + int a = visibility(s, t, region[i]); + if (a == ONLINE) return len; + if (a == CONTAINED) return weight[i] * len; + if (a == INTERSECT) return 1.0 / 0.0; + } + return len; + } + pair> shortest_path(point p, point q) { + ps.push_back(p); ps.push_back(q); + int n = ps.size(), s = n-2, t = n-1; + vector dist(n, 1.0/0.0), h(n); dist[s] = 0; + for (int u = 0; u < n; ++u) h[u] = norm(ps[u]-ps[t]); // modify here if weight < 1.0 + vector last(n, ~s); // negative -> unfixed + while (last[t] < 0) { + int u = t; + for (int v = 0; v < n; ++v) + if (last[v] < 0 && dist[v] + h[v] < dist[u] + h[u]) u = v; + last[u] = ~last[u]; + for (int v = 0; v < n; ++v) { + if (last[v] >= 0) continue; + auto len = dist[u] + length(u, v); + if (sign(dist[v] - len) > 0) { + dist[v] = len; + last[v] = ~u; + } + } + } + auto cost = dist[t]; + vector path; + if (cost < 1.0 / 0.0) { + while (t != s) { + path.push_back(t); + t = last[t]; + } + path.push_back(s); + } + ps.pop_back(); ps.pop_back(); + return {cost, path}; + } +}; + +//----------------------------------------------------------------------------- +// merge segments in O(n log n) +// [non-verified] +//----------------------------------------------------------------------------- +vector merge_segments(vector ss) { + auto compare = [&](segment s, segment t) { + int a = sign(cross(s.q-s.p, t.p-t.q)); + return a ? a < 0 : sign(cross(t.p-s.p, t.q-s.p)) < 0; + }; + for (segment &s: ss) if (s.q < s.p) swap(s.p, s.q); + sort(all(ss), compare); + vector res; + for (int i = 0, j; i < ss.size(); i = j) { + for (j = i+1; j < ss.size(); ++j) + if (compare(ss[i], ss[j])) break; + point o = ss[i].p, v = ss[i].q - ss[i].p; + sort(ss.begin()+i, ss.begin()+j, [&](segment s, segment &t) { + auto a = dot(s.p - t.p, v); + if (a) return a < 0; + return dot(s.q - t.q, v) < 0; + }); + for (int a = i, b; a < j; a = b) { + for (b = a+1; b < j; ++b) { + if (sign(dot(ss[a].q - ss[b].p, v)) < 0) break; + if (dot(ss[a].q - ss[b].q, v) < 0) ss[a].q = ss[b].q; + } + res.push_back(ss[a]); + } + } + return res; +} + +//----------------------------------------------------------------------------- +// relative neighborhood graph +// there is an edge between p and q iff +// d(p,q) < d(p,r), and d(p,q) < d(q,r) +// for all other point r. +// +// it contains euclidean mst. +// +// O(n^2) by Katajainen and Nevalainen +// +// [non-verified] +//----------------------------------------------------------------------------- +struct relative_neighborhood_graph { + struct edge { + int src, dst; + real len; + }; + int n; + vector ps; + vector> adj; + relative_neighborhood_graph(vector ps) : + n(ps.size()), ps(ps), adj(n) { + + auto quadrant = [&](point p) { + for (int i = 0; i < 8; ++i) { + if (p.x >= 0 && p.y >= 0 && p.y < p.x) return i; + p = (point){p.x + p.y, -p.x + p.y}; + } + return -1; + }; + for (int i = 0; i < n; ++i) { + vector> cand(8); + vector dist(8, 1.0/0.0); + for (int j = 0; j < n; ++j) { + if (i == j) continue; + int k = quadrant(ps[j] - ps[i]); + real d = norm2(ps[j] - ps[i]); + if (sign(d - dist[k]) < 0) cand[k] = {j}, dist[k] = d; + else if (sign(d - dist[k]) == 0) cand[k].push_back(j); + } + for (int k = 0, l; k < 8; ++k) { + //cout << dist[k] << endl; + for (int j: cand[k]) { + if (j >= i) continue; + for (l = 0; l < n; ++l) { + if (l == i || l == j) continue; + if (sign(dist[k] - norm2(ps[l] - ps[i])) > 0) break; + } + if (l == n) { + adj[i].push_back({i, j, sqrt(dist[k])}); + adj[j].push_back({j, i, sqrt(dist[k])}); + } + } + } + } + } +}; + + +// --------------------------------------------------------------------------- +// maximum area of empty convex k-gon +// +// David P. Dovkin, Harbert Edelsbrunner, and Mark H. Overmars (1990): +// Searching for Empty Convex Polygons. +// Algorithmica, vol.5, no.1, pp.561--571. +// +// Complexity: O(n^3) +// +// [non-verified] +// --------------------------------------------------------------------------- +real maximum_area_empty_convex_polygon(vector ps) { + int n = ps.size(); + real ans = 0; + for (int o = 0; o < n; ++o) { + vector vs; + for (point p: ps) + if (p < ps[o]) vs.push_back(p - ps[o]); + int m = vs.size(); + sort(all(vs), [&](point p, point q) { + int s = sign(cross(p, q)); + return s ? s > 0 : sign(dot(q,q) - dot(p,p)) > 0; + }); + vector> dp(m, vector(m)); + for (int k = 1; k < m; ++k) { + int i = k-1; + while (i >= 0 && !sign(cross(vs[i], vs[k]))) --i; + vector seq; + for (int j; i > 0; i = j) { + seq.push_back(i); + for (j = i-1; j > 0 && sign(cross(vs[i]-vs[k], vs[j]-vs[k])) > 0; --j); + auto v = cross(vs[i], vs[k]); + if (j >= 0) v += dp[i][j]; + dp[k][i] = v; + ans = max(ans, v); + } + for (int i = (int)seq.size()-2; i >= 0; --i) + dp[k][seq[i]] = max(dp[k][seq[i]], dp[k][seq[i+1]]); + } + } + return ans; +} + +//----------------------------------------------------------------------------- +// delaunay triangulation +// O(n^2) in the worst case, O(n log n) -- O(n sqrt(n)) in pratice. +// +// [verified: RUPC 2013 F] +//----------------------------------------------------------------------------- +struct delaunay { + struct edge { + int src, dst; + }; + int n; + vector ps; + vector> adj; // optional + vector inner; + int incircle(int a, int b, int c, int p) { + point u = ps[a]-ps[p], v = ps[b]-ps[p], w = ps[c]-ps[p]; + return sign(norm2(u)*cross(v,w) + +norm2(v)*cross(w,u) + +norm2(w)*cross(u,v)) > 0; + } + bool orient(int a, int b, int p) { + point u = ps[a]-ps[b], v = ps[p]-ps[b]; + int s = sign(cross(u, v)); + return s ? s > 0 : sign(dot(u, v)) > 0; + } + delaunay(vector ps) : n(ps.size()), ps(ps), adj(n), inner(n) { + if (n <= 1) return; + vector> ccw(n); // ccw[u][v] is the third pt for (u,v) + auto make_triangle = [&](int a, int b, int c) { + ccw[a][b] = c; ccw[b][c] = a; ccw[c][a] = b; + }; + vector is(n); iota(all(is), 0); + sort(all(is), [&](int i, int j) { return ps[i] < ps[j]; }); + // delaunay flips + function rec = [&](int a, int b) { + if (!ccw[a].count(b) || !ccw[b].count(a)) return; + int c = ccw[a][b], d = ccw[b][a]; + if (incircle(a, b, c, d) > 0) { + ccw[a].erase(b); ccw[b].erase(a); + make_triangle(d, c, a); + make_triangle(c, d, b); + rec(a, d); rec(d, b); rec(b, c); rec(c, a); + } + }; + // lexicographic triangulation + vector next(n,-1), prev(n,-1); + next[is[0]] = prev[is[0]] = is[1]; + next[is[1]] = prev[is[1]] = is[0]; + for (int i = 2; i < n; ++i) { + int h = is[i], u = is[i-1], v = u; + while ( orient(u, next[u], h)) u = next[u]; + while (!orient(v, prev[v], h)) v = prev[v]; + for (int w = v; w != u; w = next[w]) + if (sign(cross(ps[next[w]]-ps[h], ps[w]-ps[h])) > 0) + make_triangle(w, h, next[w]); + next[h] = u; prev[u] = h; + prev[h] = v; next[v] = h; + } + for (int u: is) { + auto nbh = ccw[u]; // hardcopy + for (auto z: nbh) rec(z.fst, z.snd); // flip + } + // complete graph structure + for (int u: is) { + int v = ccw[u].begin()->fst, s = v; + while (ccw[s].count(u)) { + s = ccw[s][u]; + if (s == v) break; + } // v != s means that u is on the outer face + if (v != s) { inner[u] = false; v = s; } + do { + adj[u].push_back({u, v}); + if (!ccw[u].count(v)) break; + v = ccw[u][v]; + } while (v != s); + } + } +}; +//----------------------------------------------------------------------------- +// voronoi diagram (from delaunay triangulation) +// O(sum deg^2) = O(n^2) in worst case, O(n) for random input. +// +// [verified: RUPC 2013 F] +//----------------------------------------------------------------------------- +struct voronoi { + struct edge { + int src, dst; + real len; + }; + int n, m; + vector ps, qs; // qs is the voronoi vertices + map id; + vector> cell; + vector> adj; + void add_edge(int u, int v) { + auto len = norm(qs[u] - qs[v]); + adj[u].push_back({u, v, len}); + adj[v].push_back({v, u, len}); + } + int node(point p) { + if (!id.count(p)) { id[p] = m++; qs.push_back(p); adj.push_back({}); } + return id[p]; + } + voronoi(delaunay DT, vector domain) : + n(DT.n), m(0), ps(DT.ps), cell(n) { + for (int u = 0; u < n; ++u) { + vector region = domain; + for (auto e: DT.adj[u]) { + point s = (ps[e.src]+ps[e.dst])/2, d = orth(ps[e.dst]-ps[e.src]); + region = convex_cut(region, {s, s+d}); + } + for (int i = 0; i < region.size(); ++i) { + add_edge(node(region[i]), node(region[(i+1)%region.size()])); + cell[u].push_back(node(region[i])); + } + } + } + voronoi(vector ps, vector domain) : + voronoi(delaunay(ps), domain) { } +}; + +/* +DCEL にしたい + +struct Delaunay { + struct Vertex; struct Edge; + struct Vertex { + point p; + Edge *edge; // any adjacent edge + }; + struct Edge { + Vertex *vertex; // origin + Edge *twin; + Edge *prev, *next; + }; + int incircle(Vertex *a, Vertex *b, Vertex *c, Vertex *p) { + point u = a->p - p->p, v = b->p - p->p, w = c->p - p->p; + return sign(norm2(u)*cross(v,w) + +norm2(v)*cross(w,u) + +norm2(w)*cross(u,v)) > 0; + } + bool orient(Vertex *a, Vertex *b, Vertex *p) { + point u = a->p - b->p, v = p->p - b->p; + int s = sign(cross(u, v)); + return s ? s > 0 : sign(dot(u, v)) > 0; + } + Delaunay(vector ps) { + + } + z d w d + / \ / | \ + 枝 a -e-> b ==> a | b + \ / \ v / + y c x c + + を逆転させる手続き + if incircle: + r = e->twin + x = e->next y = e->prev + z = r->next w = r->prev + x->vertex->edge = x + z->vertex->edge = z + w->next = x x->next = r r->next = w + w->prev = r x->prev = w r->prev = x + y->next = z z->next = e e->next = y + y->prev = e z->prev = y e->prev = z + e->vertex = w->vertex + r->vertex = y->vertex + rec(x); rec(y); rec(z); rec(w); + + Vertex *u :: rightmost + Edge *e = u->edge + while orient: e = e->prev + + span(e->next) + e->twin->next で CH を traverse できる + + while !orient: + r = new Edge, s = new Edge, t = new Edge + r->next = s s->next = t t->next = r + r->prev = b + + + + p ---- v + \ / + q / + + auto make_triangle = [&](int a, int b, int c) { + ccw[a][b] = c; ccw[b][c] = a; ccw[c][a] = b; + }; + vector is(n); iota(all(is), 0); + sort(all(is), [&](int i, int j) { return ps[i] < ps[j]; }); + // delaunay flips + function rec = [&](int a, int b) { + if (!ccw[a].count(b) || !ccw[b].count(a)) return; + int c = ccw[a][b], d = ccw[b][a]; + if (incircle(a, b, c, d) > 0) { + ccw[a].erase(b); ccw[b].erase(a); + make_triangle(d, c, a); + make_triangle(c, d, b); + rec(a, d); rec(d, b); rec(b, c); rec(c, a); + } + }; + +}; +*/ + + +//----------------------------------------------------------------------------- +// [non-verified] +//----------------------------------------------------------------------------- +bool is_congruence(polygon ps, polygon qs) { + if (ps.size() != qs.size()) return false; + int n = ps.size(); + vector as, bs; + for (int i = 0; i < n; ++i) { + int j = (i+1 < n ? i+1 : 0), k = (j+1 < n ? j+1 : 0); + as.push_back({dot(ps[i]-ps[j], ps[k]-ps[j]), + cross(ps[i]-ps[j], ps[k]-ps[j])}); + bs.push_back({dot(qs[i]-qs[j], qs[k]-qs[j]), + cross(qs[i]-qs[j], qs[k]-qs[j])}); + } + vector fail(n+1, -1); // knuth morris pratt + for (int i = 1, j = -1; i <= n; ++i) { + while (j >= 0 && !(as[j] == as[i-1])) j = fail[j]; + fail[i] = ++j; + } + for (int i = 0, k = 0; i < 2*n; ++i) { + while (k >= 0 && !(bs[i%n] == as[k])) k = fail[k]; + if (++k == n) return true; // ps[0,n) == qs[i-n+1, *) + } + return false; +} +//----------------------------------------------------------------------------- +// [non-verified] +//----------------------------------------------------------------------------- +bool is_similar(polygon ps, polygon qs) { + if (ps.size() != qs.size()) return false; + int n = ps.size(); + vector as, bs; + for (int i = 0; i < n; ++i) { + int j = (i+1 < n ? i+1 : 0), k = (j+1 < n ? j+1 : 0); + as.push_back({dot(ps[i]-ps[j], ps[k]-ps[j]), + cross(ps[i]-ps[j], ps[k]-ps[j])}); + bs.push_back({dot(qs[i]-qs[j], qs[k]-qs[j]), + cross(qs[i]-qs[j], qs[k]-qs[j])}); + } + real maxa = as[0].x, maxb = bs[0].y; + for (int i = 1; i < n; ++i) + maxa = max(maxa, as[i].x), maxb = max(maxb, bs[i].x); + vector fail(n+1, -1); // knuth morris pratt + for (int i = 1, j = -1; i <= n; ++i) { + while (j >= 0 && !(as[j] == as[i-1])) j = fail[j]; + fail[i] = ++j; + } + for (int i = 0, k = 0; i < 2*n; ++i) { + while (k >= 0 && !(maxa*bs[i%n] == maxb*as[k])) k = fail[k]; + if (++k == n) return true; // maxb * ps[0,n) == maxa * qs[i-n+1, *) + } + return false; +} +//----------------------------------------------------------------------------- +// [non-verified] +//----------------------------------------------------------------------------- +polygon simplify(polygon ps) { + int n = ps.size(); + polygon qs; + for (int i = 0; i < n; ++i) { + int j = (i+1 < n ? i+1 : 0), k = (j+1 < n ? j+1 : 0); + if (sign(dot(ps[j]-ps[i], ps[k]-ps[i])) < 0 || + sign(cross(ps[j]-ps[i], ps[k]-ps[i]))) + qs.push_back(ps[j]); + } + return qs; +} + + +//----------------------------------------------------------------------------- +// VP tree (metric tree) +// +// [non-verified] +//----------------------------------------------------------------------------- +struct vantage_point_tree { + int n; + vector ps; + vector> aux; + vantage_point_tree(vector ps) : n(ps.size()), ps(ps), aux(n) { + for (int i = 0; i < n; ++i) aux[i].snd = i; + function rec = [&](int l, int r) { + if (l == r) return; + swap(aux[l], aux[l+rand()%(r-l)]); + for (int i = l+1; i < r; ++i) + aux[i].fst = norm(ps[aux[i].snd] - ps[aux[l].snd]); + int m = (l+1 + r) / 2; + nth_element(aux.begin()+l+1, aux.begin()+m, aux.begin()+r); + aux[l].fst = aux[m].fst; + rec(l+1, m); rec(m, r); + }; + rec(0, n); + } + vector closest(point p, int k = 1) { + priority_queue> topk; + function rec = [&](int l, int r) { + int m = (l+1 + r) / 2; + if (l == r) return; + auto d = norm(p - ps[aux[l].snd]); + if (topk.size() < k) topk.push({d, aux[l].snd}); + else if (topk.top().fst > d) { + topk.pop(); + topk.push({d, aux[l].snd}); + } + if (d <= aux[l].fst) { + rec(l+1, m); + if (aux[l].fst - d < topk.top().fst) rec(m, r); + } else { + rec(m, r); + if (d - aux[l].fst < topk.top().fst) rec(l+1, m); + } + }; + rec(0, n); + vector ans; + for (; !topk.empty(); topk.pop()) ans.push_back(topk.top().snd); + reverse(all(ans)); + return ans; + } +}; + +//----------------------------------------------------------------------------- +// random ball over +// O(n f(n)) construction, O(n/f(n)) query +// If there are T queries, set f(n) = O(sqrt(T)). +// +// [non-verified] +//----------------------------------------------------------------------------- +struct random_ball_cover { + int n, m; + vector ps, cs; + vector>> vs; + random_ball_cover(vector ps) : n(ps.size()), ps(ps), cs(ps) { + for (int k = m = 1; m < n && k < n; k *= 2, ++m); // m = O(log(n)) + cs.resize(m); vs.resize(m); + for (int u = 0; u < n; ++u) { + int j = 0; + real best = norm(cs[j] - ps[u]); + for (int k = 1; k < m; ++k) { + real len = norm(cs[k] - ps[u]); + if (best > len) { best = len; j = k; } + } + vs[j].push_back({best, u}); + } + for (int j = 0; j < m; ++j) { + sort(all(vs[j])); reverse(all(vs[j])); + } + } + vector closest(point p, int k = 1) { + vector> order(m); + for (int j = 0; j < m; ++j) + order[j] = {norm(cs[j] - p), j}; + sort(all(order)); + priority_queue> topk; + for (auto ord: order) { + real rad = ord.fst; + for (auto z: vs[ord.snd]) { + if (topk.size() < k || topk.top().fst > ord.fst - z.fst) { + topk.push({norm(ps[z.snd] - p), z.snd}); + if (topk.size() > k) topk.pop(); + } else break; + } + } + vector ans; + for (; !topk.empty(); topk.pop()) ans.push_back(topk.top().snd); + reverse(all(ans)); + return ans; + } +}; + + +//----------------------------------------------------------------------------- +// Dynamic Convex Hull (Overmars-Leeuwen) +// +// Memoise divide-and-conquer procedure in segment tree. +// Each tree nodes stores convex hulls by binary search tree. +// +// [verified] CODECHEF MGCHGEOM, ACM/ICPC 2017-D +//----------------------------------------------------------------------------- + +template +struct half_hull { + struct node { + point p; + node *child[2], *parent; + node *next[2]; + + real area; + double perimeter; + }; + node *update(node *t) { + if (t) { + t->area = 0; + if (t->child[0]) t->area += t->child[0]->area + cross(t->p, t->next[0]->p); + if (t->child[1]) t->area += t->child[1]->area - cross(t->p, t->next[1]->p); + + t->perimeter = 0; + if (t->child[0]) t->perimeter += t->child[0]->perimeter + norm(t->p - t->next[0]->p); + if (t->child[1]) t->perimeter += t->child[1]->perimeter + norm(t->p - t->next[1]->p); + } + return t; + } + int dir(node *x, node *y) { return x && x->child[0] == y ? 0 : 1; } + void link(node *x, node *y, int d) { + if (x) x->child[d] = y; + if (y) y->parent = x; + } + void rot(node *x, int d) { + node *y = x->child[d], *z = x->parent; + link(x, y->child[!d], d); + link(y, x, !d); + link(z, y, dir(z, x)); + update(x); update(y); + } + void splay(node *x) { + if (!x) return; + while (x->parent) { + node *y = x->parent, *z = y->parent; + int dy = dir(y, x), dz = dir(z, y); + if (!z) { rot(y, dy); } + else if (dy == dz) { rot(z, dz), rot(y, dy); } + else { rot(y, dy), rot(z, dz); } + } + } + int n; + vector vs; + vector ch, sh; + vector ps; + half_hull(vector ps_) : ps(ps_) { + sort(all(ps)); + ps.erase(unique(all(ps)), ps.end()); + n = ps.size(); + vs.resize(n); + for (int i = 0; i < n; ++i) vs[i] = {ps[i]}; + ch.resize(4*n); sh.resize(4*n); + } + pair bridge(node *lch, node *rch) { + if (lch && rch) { + while (1) { + int it = 0; + for (splay(rch); ; ++it) { + if (rch->next[0] && turn*sign(cross(rch->next[0]->p - lch->p, rch->p - lch->p)) <= 0) { + rch = rch->child[0]; + } else if (rch->next[1] && turn*sign(cross(rch->p - lch->p, rch->next[1]->p - lch->p)) > 0) { + rch = rch->child[1]; + } else break; + } + for (splay(lch); ; ++it) { + if (lch->next[1] && turn*sign(cross(lch->p - rch->p, lch->next[1]->p - rch->p)) <= 0) { + lch = lch->child[1]; + } else if (lch->next[0] && turn*sign(cross(lch->next[0]->p - rch->p, lch->p - rch->p)) > 0) { + lch = lch->child[0]; + } else break; + } + if (it == 0) break; + } + } else if (lch) { + for (splay(lch); lch->child[1]; lch = lch->child[1]); + } else if (rch) { + for (splay(rch); rch->child[0]; rch = rch->child[0]); + } + return {lch, rch}; + } + node *apart(node *x, int d) { + if (!x) return 0; + node *y = x->child[d]; + if (!y) return 0; + y->parent = x->child[d] = 0; + for (; y->child[!d]; y = y->child[!d]); + splay(y); + x->next[d] = y->next[!d] = 0; + update(x); + return y; + } + node *join(node *x, node *y) { + if (!x) return y; + if (!y) return x; + x->child[1] = x->next[1] = y; + y->parent = y->next[0] = x; + update(x); + return x; + } + template + void build(int l, int r, int k, int i) { + if (l+1 == r) { ch[k] = I ? &vs[i] : 0; return; } + splay(ch[2*k+1]); + apart(ch[2*k+1], 1); + ch[2*k+1] = join(ch[2*k+1], sh[2*k+1]); + splay(ch[2*k+2]); + ch[2*k+2] = join(sh[2*k+2], ch[2*k+2]); + if (i < (l+r)/2) build(l, (l+r)/2, 2*k+1, i); + else build((l+r)/2, r, 2*k+2, i); + tie(ch[2*k+1], ch[2*k+2]) = bridge(ch[2*k+1], ch[2*k+2]); + splay(ch[2*k+1]); + splay(ch[2*k+2]); + sh[2*k+1] = apart(ch[2*k+1], 1); + sh[2*k+2] = apart(ch[2*k+2], 0); + ch[k] = join(ch[2*k+1], ch[2*k+2]); + } + int index(point p) const { return lower_bound(all(ps), p) - ps.begin(); } + void insert(point p) { build<1>(0, n, 0, index(p)); } + void erase(point p) { build<0>(0, n, 0, index(p)); } + + node *find(point p) { + node *t = ch[0]; + while (t && t->p != p) + t = t->child[t->p < p]; + return t; + } +}; +struct dynamic_convex_hull { + half_hull<+1> upper; + half_hull<-1> lower; + + dynamic_convex_hull(vector ps) : upper(ps), lower(ps) { } + void insert(point p) { upper.insert(p); lower.insert(p); } + void erase(point p) { upper.erase(p); lower.erase(p); } + + real area() { + real area = 0; + if (upper.ch[0]) area += upper.ch[0]->area; + if (lower.ch[0]) area -= lower.ch[0]->area; + return area; + } + double perimeter() { + double perimeter = 0; + if (upper.ch[0]) perimeter += upper.ch[0]->perimeter; + if (lower.ch[0]) perimeter += lower.ch[0]->perimeter; + return perimeter; + } + + struct hull_iterator { + half_hull<+1>::node *upper_ptr; + half_hull<-1>::node *lower_ptr; + hull_iterator(half_hull<+1>::node *upper_ptr, half_hull<-1>::node *lower_ptr) : + upper_ptr(upper_ptr), lower_ptr(lower_ptr) { } + + bool operator==(hull_iterator it) { + auto is_end = [&](hull_iterator it) { return !it.upper_ptr && !it.lower_ptr; }; + if (is_end(*this) && is_end(it)) return true; + if (is_end(*this) || is_end(it)) return false; + return *(*this) == *it; + } + bool operator!=(hull_iterator it) { return !operator==(it); } + void operator++() { + if (upper_ptr) upper_ptr = upper_ptr->next[1]; + if (!upper_ptr) { + lower_ptr = lower_ptr->next[0]; + if (lower_ptr && !lower_ptr->next[0]) lower_ptr = 0; + } + } + point operator*() { + return upper_ptr ? upper_ptr->p : lower_ptr->p; + } + }; + hull_iterator begin() { + if (!upper.ch[0]) return hull_iterator(0, 0); + auto upper_ptr = upper.ch[0]; + for (; upper_ptr->child[0]; upper_ptr = upper_ptr->child[0]); + auto lower_ptr = lower.ch[0]; + for (; lower_ptr->child[1]; lower_ptr = lower_ptr->child[1]); + return hull_iterator(upper_ptr, lower_ptr); + } + hull_iterator end() { return hull_iterator(0, 0); } + hull_iterator find(point p) { + hull_iterator it = begin(); + it.upper_ptr = upper.find(p); + if (!it.upper_ptr) it.lower_ptr = lower.find(p); + return it; + } + hull_iterator next(hull_iterator it) { + ++it; + if (it == end()) it = begin(); + return it; + } +}; + +int ACMICPC_JP_2017D() { + int n; + scanf("%d", &n); + vector ps; + for (int i = 0; i < n; ++i) { + double x, y; + scanf("%lf %lf", &x, &y); + ps.push_back({x, y}); + } + dynamic_convex_hull hull(ps); + for (int i = 0; i < n; ++i) + hull.insert(ps[i]); + + double per = hull.perimeter(); + double best1 = 0; + { // best non-adjacent + vector> top; + for (auto it = hull.begin(); it != hull.end(); ++it) { + hull.erase(*it); + top.push_back({per - hull.perimeter(), *it}); + hull.insert(*it); + } + sort(all(top)); reverse(all(top)); + for (int i = 0; i < min(4, (int)top.size()); ++i) { + point p = top[i].snd; + for (int j = i+1; j < min(4, (int)top.size()); ++j) { + point q = top[j].snd; + auto it = hull.next(hull.find(p)); + if (*it == q) continue; + it = hull.next(hull.find(q)); + if (*it == p) continue; + best1 = max(best1, top[i].fst + top[j].fst); + } + } + } + double best2 = 0; + { // best consecurive two + for (auto it = hull.begin(); it != hull.end(); ++it) { + auto jt = hull.next(it); + hull.erase(*it); + hull.erase(*jt); + best2 = max(best2, per - hull.perimeter()); + hull.insert(*it); + hull.insert(*jt); + } + } + double best3 = 0; + { // best successive two + for (auto it = hull.begin(); it != hull.end(); ++it) { + auto jt = hull.next(it), kt = hull.next(jt); + hull.erase(*jt); + for (auto lt = it; lt != kt; lt = hull.next(lt)) { + hull.erase(*lt); + best3 = max(best3, per - hull.perimeter()); + hull.insert(*lt); + } + hull.insert(*jt); + } + } + printf("%.5f\n", max({best1, best2, best3})); +} + +//----------------------------------------------------------------------------- +// kd-tree with distance biseparator. +// +// if we construct naively, it tooks O(n^2). +// using candle burning method (by Bentley), it can construct in O(n log n). +// The following implementation is lazy so O(n log^2 n). +//----------------------------------------------------------------------------- +struct split_tree { + struct node { + node *l, *r; + int d; + point h; + int id; + } *root; + int n; + vector ps; + pair ref(pair p) { + return {{p.fst.y, p.fst.x}, p.snd}; + } + split_tree(vector ps) : n(ps.size()), ps(ps) { + set> s[2]; + for (int i = 0; i < n; ++i) { + pair z = {ps[i], i}; + s[0].insert(z); + s[1].insert(ref(z)); + } + function>*)> rec = [&](set> s[]) { + if (s[0].empty()) return (node*)0; + if (s[0].size() == 1) { + int id = s[0].begin()->snd; + return new node({0, 0, -1, ps[id], id}); + } + int d = 0; + if (prev(s[0].end())->fst - s[0].begin()->fst < + prev(s[1].end())->fst - s[1].begin()->fst) d = 1; + auto it = s[d].begin(), jt = prev(s[d].end()); + point h = (jt->fst + it->fst) / 2; // left if smaller than h + while (1) { + if (it == jt || h <= it->fst) break; ++it; + if (it == jt || jt->fst < h) break; --jt; + } + node *l, *r; + set> ss[2]; + if (it->fst < h) { // violate jt side + ++jt; + do { + ss[!d].insert(ref(*jt)); + s[!d].erase(ref(*jt)); + ss[d].insert(*jt); + jt = s[d].erase(jt); + } while (jt != s[d].end()); + r = rec(ss); + l = rec(s); + } else { // violate it side + do { + --it; + ss[!d].insert(ref(*it)); + s[!d].erase(ref(*it)); + ss[d].insert(*it); + it = s[d].erase(it); + } while (it != s[d].begin()); + l = rec(ss); + r = rec(s); + } + return new node({l, r, d, h, -1}); + }; + root = rec(s); + } + + int depth(node *u) { + if (!u) return 0; + return 1+max(depth(u->l), depth(u->r)); + } + void disp(node *u, int tab = 0) { + if (!u) return; + if (u->d < 0) { + cout << string(tab, ' ') << u->h << endl; + return; + } else { + cout << string(tab, ' ') << "split at " << (u->h) << " (" << u->d << ")" << endl; + disp(u->l, tab+2); + disp(u->r, tab+2); + } + } +}; + +// naive. O(n^2) in worst case. or O(n log(largest gap/smallest gap)) +struct split_tree_n { + struct node { + node *l, *r; + int d; + point h; + int id; + } *root; + + int n; + vector ps; + pair ref(pair p) { + return {{p.fst.y, p.fst.x}, p.snd}; + } + split_tree_n(vector ps) : n(ps.size()), ps(ps) { + function)> rec = [&](vector id) { + if (id.size() == 0) return (node*)0; + if (id.size() == 1) { + return new node({0, 0, -1, ps[id[0]], id[0]}); + } + vector xs, ys; + for (int i: id) { + xs.push_back(ps[i].x); + ys.push_back(ps[i].y); + } + sort(all(xs)); + sort(all(ys)); + if (xs.back() - xs[0] > ys.back() - ys[0]) { + real d = (xs.back()+xs[0])/2; + vector ls, rs; + for (int i: id) { + if (ps[i].x < d) ls.push_back(i); + else rs.push_back(i); + } + return new node({rec(ls), rec(rs), 0, {d,0}, -1}); + } else { + real d = (ys.back()+ys[0])/2; + vector ls, rs; + for (int i: id) { + if (ps[i].y < d) ls.push_back(i); + else rs.push_back(i); + } + return new node({rec(ls), rec(rs), 1, {0,d}, -1}); + } + }; + vector id(n); iota(all(id), 0); + root = rec(id); + } + + int depth(node *u) { + if (!u) return 0; + return 1+max(depth(u->l), depth(u->r)); + } + void disp(node *u, int tab = 0) { + if (!u) return; + if (u->d < 0) { + cout << string(tab, ' ') << u->h << endl; + return; + } else { + cout << string(tab, ' ') << "split at " << (u->h) << " (" << u->d << ")" << endl; + disp(u->l, tab+2); + disp(u->r, tab+2); + } + } +}; + +// TODO +// https://graphics.stanford.edu/courses/cs468-06-fall/Papers/02%20vladlen%20notes.pdf +// epsilon net +// Let (X, F) be a set system. N \subset X is called epsilon net if +// N cat S \neq empty for all S in F with u(S) > epsilon. +// (if S in F has area greater than epsilon, S intersect with N). +// +// Theorem. there exists e-net of size O(d (1/e) log(1/e)) +// + + + +// vor(i) is the polygon such that for all p in vor(i) +// ps[i] is the farthest point from p. +// +// clearly: vor(i) is non-empty if ps[i] is on the convex hull. +// +// TODO +struct farthest_voronoi { + int n; + vector ps, qs; + map id; + /* + int node(point p) { + if (!id.count(p)) { id[p] = m++; qs.push_back(p); adj.push_back({}); } + return id[p]; + } + */ + vector> vor; + + farthest_voronoi(vector ps, vector domain) : + n(ps.size()), ps(ps) { + vector id(n); iota(all(id), 0); + sort(all(id), [&](int i, int j) { return ps[i] < ps[j]; }); + + vector ch(2*n); + auto cond = [&](int i, int j, int k) { + return sign(cross(ps[i]-ps[k], ps[j]-ps[k])) < 0; + }; + int k = 0; + for (int i = 0; i < n; ch[k++] = i++) + for (; k >= 2 && cond(ch[k-2], ch[k-1], i); --k); + for (int i = n-2, t = k+1; i >= 0; ch[k++] = i--) + for (; k >= t && cond(ch[k-2], ch[k-1], i); --k); + ch.resize(k-1); + + cout << ch << endl; + + vector prev(n, -1), next(n, -1); + for (int i = 0; i < ch.size(); ++i) { + int j = i + 1; if (j >= ch.size()) j = 0; + next[ch[i]] = ch[j]; + prev[ch[j]] = ch[i]; + } + + auto disp = [&](int s) { + int u = s; + do { + cout << u << " "; + u = next[u]; + } while (u != s); + cout << endl; + }; + shuffle(all(ch), mt19937()); + vor.resize(n); + for (int i = (int)ch.size()-1; i >= 1; --i) { + disp(ch[0]); + next[prev[ch[i]]] = next[ch[i]]; + prev[next[ch[i]]] = prev[ch[i]]; + } + // つらい + // 基本 DCEL がらみはしんどい + vor[ch[0]] = domain; + cout << "---" << endl; + for (int i = 1; i < ch.size(); ++i) { + next[prev[ch[i]]] = ch[i]; + prev[next[ch[i]]] = ch[i]; + disp(ch[0]); + // ch[i] と next[ch[i]] の bisector で切る + // 領域を hyperplane で管理するのが良いのか + /* + for (int j = 0; j < i; ++j) { + point s = (ps[e.src]+ps[e.dst])/2, d = orth(ps[e.dst]-ps[e.src]); + region = convex_cut(region, {s, s+d}); + } + */ + } + + // ランダムに挿入しながら構築する. + // 点 i を挿入するとき.next[i] の voronoi region を i, next[i] の bisector で切る + // bisector があたる領域を j の voronoi region として i, j の bisector で切る + // これを繰り返す + // + // データ構造処理がデス辛い + // + // 必要な演算 + // voronoi region の辺集合 + + } + +}; + +/* +struct doubly_connected_edge_list { + struct Vertex; + struct Edge; + struct Face; + struct vertex { + Edge *edge; // any incident edge + point p; // + }; + struct Edge { + Vertex *vertex; // origin + Edge *prev, *next; // surrounding edges of face + Edge *twin; // reverse edge of e + Face *face; // left face + }; + struct Face { + Edge *edge; // Any incident edge + }; + + // process edges incident to v in CCW order + void incident(Vertex *v) { + Edge *e = vertex->edge; + do { + // process e + e = e->prev->twin; + } while (e != v->edge) + v->edge; + } + // process vertices incident to e in SRC-DST order + void incident(Edge *e) { + // process e->vertex; + // process e->twin->vertex; + } + // process edges incident to f in CCW order + void incident(Face *f) { + Edge *e = f->edge; + do { + // process e + e = e->next; + } while (e != f->edge); + } +}; +*/ + +// +// Polyhedral Region Overlay +// +struct DCEL { + struct Vertex; + struct Edge; + struct Vertex { + point p; + Edge *edge; + }; + struct Edge { + Vertex *vertex; + Edge *twin; + Edge *prev, *next; + // Face *face; + }; + + DCEL copy() { + + } +}; +void overlay(DCEL *a, DCEL *b) { + // + // a と b で segment intersection をとく + // 各 intersection について新しい点をおいて edge を分割 + // その後,face を assign する + // +}; + + +// Convex Hull of circles; めっちゃバグってる +// +// divide and conquer?? +// +// 2つの凸包から,それらの union の凸包を作ればいい +// +// 最も右端にある円を選び,真上への接直線を引く +// dominant なほうを追加する +// +// TODO +// http://ac.els-cdn.com/092577219290015K/1-s2.0-092577219290015K-main.pdf?_tid=f2321600-62e3-11e6-aa7a-00000aacb35e&acdnat=1471264364_f7d8c0796b081532ec0e84e22028f111 +// +// [non-verified; in progress] +vector convex_hull(vector cs) { + int n = cs.size(); + typedef vector hull; + function merge = [&](hull P, hull Q) { + cout << "---" << endl; + cout << "merge "; + for (auto i: P) cout << "[" << cs[i].p << "," << cs[i].r << "] "; + cout << "and"; + for (auto j: Q) cout << " [" << cs[j].p << "," << cs[j].r << "]"; + cout << endl; + hull S; + unordered_set elem; + auto add = [&](int k) { + if (elem.count(k)) return; + cout << "add [" << cs[k].p << "," << cs[k].r << "]" << endl; + S.push_back(k); + elem.insert(k); + }; + auto supp = [&](int k, point v) { + circle c = cs[k]; + return c.p - c.r * orth(v); + }; + auto dom = [&](int i, int j, point v) { + point p = supp(P[i], v), q = supp(Q[j], v); + cout << "p = " << p << ", q = " << q << endl; + int s = sign(cross(p - q, v)); + cout << "s = " << s << endl; + return s ? s > 0 : sign(dot(q - p, v)) > 0; + }; + auto tangent = [&](int k, int l) { + if (k == l) return point({0,0}); + auto u = cs[l].p - cs[k].p; + auto b = cs[k].r - cs[l].r, g = norm(u); + u /= g; + auto h = b / g; + cout << h << endl; + if (sign(1 - h*h) < 0) return point({0,0}); + return orth(u*h - orth(u)*sqrt(max(0.0l, 1 - h*h))); + }; + auto compare = [&](point a, point b, point v) { + cout << "compare " << a << " " << b << " " << v << endl; + if (sign(dot(a,a)) == 0) return false; + if (sign(dot(b,b)) == 0) return true; + // TODO: v と a, b は同じ方向ではいけない(大丈夫?) + // a はゼロかもしれない + int s = sign(cross(v, a)), t = sign(cross(v, b)); + cout << "s = " << s << ", t = " << t << endl; + if (s == 0 && dot(v, a) > 0) return true; + if (t == 0 && dot(v, b) > 0) return false; + return s != t ? s > t : sign(cross(a, b)) > 0; + }; + auto advance = [&](int &i, int &j, point &v) { + int I = (i+1) % P.size(), J = (j+1) % Q.size(); + point a = tangent(P[i], Q[j]), b = tangent(P[i], P[I]), + c = tangent(Q[j], Q[J]), d = tangent(Q[j], P[i]); + cout << a << " " << b << " " << c << " " << d << endl; + if (compare(a, b, v) && compare(a, c, v)) { cout << a << " is the first turn" << endl; add(Q[j]); } + if (compare(d, b, v) && compare(d, c, v)) { cout << d << " is the first turn" << endl; add(P[i]); } + if (compare(b, c, v)) { v = b; i = I; } + else { v = c; j = J; } + }; + int i = 0, j = 0; + point v = {1, 0}; + for (int iter = 0; iter < 3+P.size()+Q.size(); ++iter) { + if (sign(norm(v)) == 0) break; + cout << "currently " << cs[P[i]].p << " and " << cs[Q[j]].p << endl; + if (dom(i, j, v)) { + cout << cs[P[i]].p << " is the lowermost" << endl; + add(P[i]); + } else { + cout << cs[Q[j]].p << " is the lowermost" << endl; + add(Q[j]); + } + advance(i, j, v); + } + cout << "==> "; + for (auto i: S) cout << "[" << cs[i].p << "," << cs[i].r << "] "; + cout << endl; + return S; + }; + function rec = [&](int l, int r) { + if (l+1 == r) return (hull){l}; + auto P = rec(l, (l+r)/2), Q = rec((l+r)/2, r); + return merge(P, Q); + }; + auto ch = rec(0, n); + vector res; + for (int i: ch) res.push_back(cs[i]); + return res; +} + +void verify_convex_hull_discs() { + int n = 20; + vector cs; + for (int i = 0; i < n; ++i) + cs.push_back({ {urand(), urand()}, urand()/3 }); + auto ch = convex_hull(cs); + + visualizer vis; + for (auto c: cs) vis << c; + point shift = point({vis.maxx+1, 0}); + for (auto c: ch) vis << circle({c.p + shift, c.r}); +} + +void verify_farthest_voronoi() { + + vector ps = { + {0,0}, + {2,0}, + {1,1}, + {2,2}, + {0,2}, + }; + vector region = { + {-10,-10}, + { 10,-10}, + { 10, 10}, + {-10, 10} + }; + farthest_voronoi V(ps, region); +} + + +// verify +// +void verify_delaunay() { + { + vector ps = { + //{0,0}, {1,0}, {1,1}, + /* + {0,0}, {0,1}, {0,2}, + {1,0}, {1,1}, + */ + /* + {0,0}, {1,0}, {2,0}, + {0,1}, {1,1}, {2,1}, + {0,2}, {1,2}, {2,2}, + */ + }; + } + int n = 100000; + vector ps(n); + for (int i = 0; i < n; ++i) + ps[i].x = urand(), ps[i].y = urand(); + tick(); + delaunay DT(ps); + cout << tick() << endl; + + visualizer vis; + for (point p: ps) vis << p; + for (int u = 0; u < DT.n; ++u) { + for (auto e: DT.adj[u]) + vis << segment({ps[e.src], ps[e.dst]}); + } + /* + for (int n = 5; n < 7; n *= 1.5) { + vector ps(n); + for (int i = 0; i < n; ++i) + ps[i].x = 100 * urand(), ps[i].y = 100 * urand(); + delaunay DT(ps); + } + */ +} +void verify_voronoi() { + /* + vector ps = { + {0,0}, {1,0}, {0,1} + }; + */ + for (int n = 5; n < 100000; n *= 1.5) { + vector ps(n); + for (int i = 0; i < n; ++i) + ps[i].x = urand(), ps[i].y = urand(); + + vector region = { + {-0.1,-0.1}, + { 1.1,-0.1}, + { 1.1, 1.1}, + {-0.1, 1.1} + }; + cout << "n = " << n << " "; + voronoi Vor(ps, region); + + visualizer vis; + for (point p: ps) vis << p; + for (int u = 0; u < Vor.m; ++u) { + //vis << Vor.qs[u]; + for (auto e: Vor.adj[u]) + vis << segment({Vor.qs[e.src], Vor.qs[e.dst]}); + } + } +} + +void POJ2235() { + for (int n; ~scanf("%d", &n); ) { + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + delaunay DT(ps); + } +} +void AOJ1514() { + for (int n, m; scanf("%d %d", &n, &m); ) { + if (n == 0) break; + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + delaunay DT(ps); + vector score(n); + double ans = 0.0; + for (int j = 0; j < m; ++j) { + point c, d; + double s; + scanf("%lf %lf %lf %lf %lf", &c.x, &c.y, &d.x, &d.y, &s); + vector domain = { + c + point({-d.x, -d.y}), + c + point({+d.x, -d.y}), + c + point({+d.x, +d.y}), + c + point({-d.x, +d.y}), + }; + voronoi V(DT, domain); + visualizer vis; + for (point p: ps) vis << p; + for (int u = 0; u < V.m; ++u) { + for (auto e: V.adj[u]) + vis << segment({V.qs[e.src], V.qs[e.dst]}); + } + vector &qs = V.qs; + for (int i = 0; i < n; ++i) { + real area = 0; + int K = V.cell[i].size(); + for (int k = 0; k < K; ++k) + area += cross(qs[k], qs[(k+1)%K]); + score[i] += s * area / 2 / (4 * d.x * d.y); + ans = max(ans, score[i]); + } + } + printf("%.12lf\n", ans); + } +} + +void verify_rectangle_union() { + vector rs = { + { {0,0},{2,2} }, + { {1,1},{4,2} }, + { {3,0},{5,2} }, + }; + cout << rectangle_union(rs) << endl; +} + +void verify_relative_neighborhood_graph() { + vector ps = { + {0,0}, + {1,0}, + {0,1}, + {1,1} + }; + relative_neighborhood_graph rng(ps); + for (int u = 0; u < rng.n; ++u) { + for (auto e: rng.adj[u]) { + cout << ps[e.src] << " " << ps[e.dst] << endl; + } + } +} + + +void verify_nearest_neighbor_structure() { + int n = 1000000, m = 100, k = 10; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = urand(); + ps[i].y = urand(); + } + tick(); + vantage_point_tree VPT(ps); + cout << "vantage point tree: " << tick() << endl; + random_ball_cover RBC(ps); + cout << "random ball cover: " << tick() << endl; + + double t1 = 0, t2 = 0; + for (int i = 0; i < m; ++i) { + point p; + p.x = urand(); + p.y = urand(); + + cout << "---" << endl; + tick(); + cout << VPT.closest(p, k) << endl; + t1 += tick(); + cout << RBC.closest(p, k) << endl; + t2 += tick(); + } + cout << "vantage point tree: " << t1 << endl; + cout << "random ball over: " << t2 << endl; +} + + + +void verify_points_counter() { + vector ps = { + {0,1}, + {1,0}, + {1,1}, + {2,1}, + }; + points_counter T(ps); +} + + + + + + + + + +void verify_intersectCC() { + auto th = 3.141592653589*rand()/(1.0+RAND_MAX); + auto dx = 1 - 2*rand()/(1.0+RAND_MAX); + auto dy = 1 - 2*rand()/(1.0+RAND_MAX); + auto S = [&](point p) { + real c = cos(th), s = sin(th); + p.x -= dx; p.y -= dy; + return (point){c * p.x + s * p.y, -s * p.x + c*p.y}; + }; + auto T = [&](circle C) { + return (circle){ S(C.p), C.r }; + }; + { + circle C = { {0,0}, 1 }; + circle D = { {2,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 1); // touch outer + } + { + circle C = { {0,0}, 1 }; + circle D = { {1,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 2); // properly intersect inner + } + { + circle C = { {0,0}, 2 }; + circle D = { {1,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 1); // intersect inner + } + { + circle C = { {0,0}, 2 }; + circle D = { {3,0}, 2 }; + TEST(intersect(T(C), T(D)).size(), 2); // properly intersect outer + } + { + circle C = { {0,0}, 3 }; + circle D = { {1,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 0); // too close + } + { + circle C = { {0,0}, 1 }; + circle D = { {3,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 0); // too far + } +} + +void verify_three_point_circle() { + for (int iter = 0; iter < 100; ++iter) { + point p = {urand(), urand()}; + point q = {urand(), urand()}; + point r = {urand(), urand()}; + circle c = three_point_circle(p, q, r); + TEST(dot(c.p - p, c.p - p), dot(c.p - q, c.p - q)); + TEST(dot(c.p - p, c.p - p), dot(c.p - r, c.p - r)); + } +} + +void verify_triangulate() { + vector ps; + ps.push_back({0, 0}); + ps.push_back({2, 0}); + ps.push_back({2, 2}); + ps.push_back({1, 1}); + ps.push_back({0, 2}); + TEST(triangulate(ps), area(ps)); +} + +void verify_convex_cut() { + int n; + scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) { + scanf("%lf %lf", &ps[i].x, &ps[i].y); + } + int m; + scanf("%d", &m); + for (int i = 0; i < m; ++i) { + line L; + scanf("%lf %lf %lf %lf", &L.p.x, &L.p.y, &L.q.x, &L.q.y); + vector qs = convex_cut(ps, L); + printf("%f\n", area(qs)); + } +} +void verify_convex_cut2() { + vector ps = { + {0.,0.}, + {1.,0.}, + {2.,0.}, + {2.,1.}, + {2.,2.}, + {1.,2.}, + {0.,2.}, + {0.,1.} + }; + line L = {{1,0},{1.5,0}}; + vector qs = convex_cut(ps, L); + for (auto q: qs) cout << q << " "; cout << endl; +} +void verify_tangent() { + point p; + circle c; + scanf("%lf %lf", &p.x, &p.y); + scanf("%lf %lf %lf", &c.p.x, &c.p.y, &c.r); + vector ps; + for (auto L: tangent(c, p)) { + if (L.p == p) ps.push_back(L.q); + else ps.push_back(L.p); + } + sort(all(ps)); + for (auto p: ps) + printf("%.12f %.12f\n", p.x + EPS, p.y + EPS); +} +void verify_tangentCC() { + TEST(tangent({{-2.0, 0.0}, 2.0}, {{-2.0, 0.0}, 1.0}).size(), 0); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{-1.0, 0.0}, 1.0}).size(), 1); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{-0.5, 0.0}, 1.0}).size(), 2); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{+1.0, 0.0}, 1.0}).size(), 3); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{+2.0, 0.0}, 1.0}).size(), 4); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{+2.0, 0.0}, 1.0}).size(), 0); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{+1.0, 0.0}, 1.0}).size(), 1); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{+0.5, 0.0}, 1.0}).size(), 2); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{-1.0, 0.0}, 1.0}).size(), 3); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{-2.0, 0.0}, 1.0}).size(), 4); + + for (int iter = 0; iter < 100; ++iter) { + circle c = {{urand(), urand()}, urand()}; + circle d = {{urand(), urand()}, urand()}; + for (line l: tangent(c, d)) { + TEST(intersect(l, c).size(), 1); + TEST(intersect(l, d).size(), 1); + } + } +} +void verify_tangentCC2() { + circle c, d; + cin >> c.p.x >> c.p.y >> c.r; + cin >> d.p.x >> d.p.y >> d.r; + vector ls = tangent(c, d); + vector ps; + for (line l: ls) { + ps.push_back(intersect(l, c)[0]); + } + sort(all(ps)); + for (point p: ps) { + double x = p.x; if (sign(x) == 0) x = 0; + double y = p.y; if (sign(y) == 0) y = 0; + printf("%.12f %.12f\n", x, y); + } +} +void verify_intersect_area() { + vector ps = { + {0.,0.}, + {3.,0.}, + {0.,3.}, + }; + circle c = {{0.0,0.0},2.8}; + cout << intersection_area(ps, c) << endl; +} + +void verify_closest_pair() { + double t1 = 0, t2 = 0; + for (int seed = 3; seed < 100; ++seed) { + srand(seed); + int n = 20000; + vector ps; + for (int i = 0; i < n; ++i) { + ps.push_back({urand(), urand()}); + } + tick(); + auto uv = closest_pair(ps); + t1 += tick(); + auto wx = closest_pair2(ps); + t2 += tick(); + auto d1 = dist(uv.fst, uv.snd); + auto d2 = dist(wx.fst, wx.snd); + cout << uv.fst << " " << uv.snd << " " << dist(uv.fst, uv.snd) << endl; + cout << wx.fst << " " << wx.snd << " " << dist(wx.fst, wx.snd) << endl; + cout << endl; + if (sign(d1 - d2) != 0) { + cout << seed << endl; + break; + } + } + cout << t1 << " " << t2 << endl; +} + +vector half_plane_intersection_n(vector ls) { + real s = 99999999; + vector ps = {{-s,-s},{s,-s},{s,s},{-s,s}}; + for (int i = 0; i < ls.size(); ++i) + ps = convex_cut(ps, ls[i]); + return ps; +} +void verify_half_plane_intersection() { + for (int seed = 0; seed < 1000; ++seed) { + srand(seed); + int n = 3 + rand() % 100; + vector ls; + for (int i = 0; i < n; ++i) { + double th1 = 2 * PI * i / n; + double th2 = 2 * PI * (i+1) / n; + double r1 = 10 + 100 * urand(); + double r2 = 10 + 100 * urand(); + ls.push_back({{r1*cos(th1), r1*sin(th1)}, + {r2*cos(th2), r2*sin(th2)}}); + } + auto a1 = area(half_plane_intersection(ls)); + auto a2 = area(half_plane_intersection_n(ls)); + if (sign(1 - a2/a1)) { cout << a1 << " " << a2 << " " << 1 - a2/a1 << " " << sign(1-a2/a1) << seed << endl; exit(-1); } + } +} + +// TEST +void angular_sort_n(vector &ps) { + vector> qs; + for (point p: ps) { + qs.push_back(make_tuple(arg(p), norm2(p), p)); + if (get<0>(qs.back()) < 0) get<0>(qs.back()) += 2 * PI; + } + sort(all(qs)); + for (int i = 0; i < ps.size(); ++i) + ps[i] = get<2>(qs[i]); +} +void verify_polar_angle() { + double t1 = 0, t2 = 0; + int n = 1000000; + vector ps; + for (int i = 0; i < n; ++i) + ps.push_back({(double)(rand()%2001)-1000, (double)(rand()%2001)-1000}); + vector qs = ps; + tick(); + sort(all(ps), polar_angle()); + t1 += tick(); + angular_sort_n(qs); + t2 += tick(); + for (int i = 0; i < ps.size(); ++i) { + if (!(ps[i] == qs[i])) { cout << "*"; } + //cout << ps[i] << " " << qs[i] << endl; + } + cout << t1 << " " << t2 << endl; +} + +void verify_maximum_circle_cover() { + int n = 10000; + vector ps; + for (int i = 0; i < n; ++i) { + double x = rand() % 1000, y = rand() % 1000; + ps.push_back({x, y}); + } + tick(); + cout << maximum_circle_cover(ps, 20) << endl; + cout << tick() << endl; + cout << maximum_circle_cover2(ps, 20) << endl; + cout << tick() << endl; +} +void verify_maximum_circle_cover2() { + for (int n; scanf("%d", &n) && n; ) { + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + printf("%d\n", maximum_circle_cover2(ps, 1.0)); + } +} + + +void verify_circle_intersection_area() { + circle c = {{0,0}, 2}; + circle d = {{2.8,0}, 1}; + cout << intersection_area(c, d) << endl; + + // Monte-Carlo integration + real w = 10.0, vol = w*w; // w times w box centered at (0,0) + int count = 0, maxcount = 100000000; + for (int i = 0; i < maxcount; ++i) { + point p = {w*urand() - w/2, w*urand() - w/2}; + if (contains(c, p) && contains(d, p)) ++count; + } + real r = 1.0*count/maxcount; + real mu = vol * r, sigma = vol*sqrt((r-r*r)/maxcount); + cout << "95\% confidence: [" << mu-3*sigma << ", " << mu+3*sigma << "]" << endl; +} + +void verify_geometric_median() { + int n = 10; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = urand(); + ps[i].y = urand(); + } + cout << geometric_median(ps) << endl; +} +void verify_geometric_median2() { + while (1) { + vector ps(4); + for (int i = 0; i < 4; ++i) + cin >> ps[i].x >> ps[i].y; + if (ps[0].x < 0) break; + point g = geometric_median(ps); + //cout << g << endl; + double w = 0; + for (int i = 0; i < 4; ++i) + w += norm(ps[i] - g); + printf("%.4f\n", w); + } +} +void verify_tangent_circles() { + line l = { {0,0},{1,0} }; + line m = { {0,2},{1,2} }; + for (circle c: tangent_circles(l, m, 1.0)) { + cout << c.p << " " << c.r << endl; + cout << " "; for (point p: intersect(c, l)) { cout << p << " "; } cout << endl; + cout << " "; for (point p: intersect(c, m)) { cout << p << " "; } cout << endl; + } +} + + +void verify_arrangement() { + vector ss = { + {{0,0},{2,0}}, + {{3,0},{5,0}}, + {{1,0},{4,0}} + }; + arrangement arr(ss); +} + +void verify_is_congruence() { + int n = 10; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i] = {urand(), urand()}; + } + double r = urand(); + point u = {urand(), urand()}; + double c = urand(), s = sqrt(1 - c*c); + vector qs; + for (int i = 0; i < ps.size(); ++i) { + qs.push_back(r * (point){c*ps[i].x+s*ps[i].y, -s*ps[i].x+c*ps[i].y} + u); + } + int k = rand() % qs.size(); + rotate(qs.begin(), qs.begin()+k, qs.end()); + cout << is_congruence(ps, qs) << endl; + cout << is_similar(ps, qs) << endl; +} + + +void verify_merge_segment() { + vector ss = { + {{0,0},{2,0}}, + {{0,0},{0,2}}, + {{4,0},{7,0}}, + {{5,0},{6,0}}, + }; + merge_segments(ss); +} +void verify_farthest_pair() { + int n = 30; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = rand() % 10; + ps[i].y = rand() % 10; + } + auto ans = farthest_pair(ps); + + real best = -1; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + best = max(best, norm(ps[i]-ps[j])); + } + } + + cout << norm(ans.fst-ans.snd) << " " << best << endl; +} + +void ACAC002() { + int n; cin >> n; + vector ps(n); + for (int i = 0; i < n; ++i) + cin >> ps[i]; + auto ans = farthest_pair(ps); + printf("%.12f\n", norm(ans.snd-ans.fst)); +} + +void verify_split_tree() { + for (int n = 1; n < 1000000; n *= 2) { + vector ps; + double x = 1, y = 0; + for (int i = 0; i < n; ++i) { + x *= 1.001; + y = 0; //rand() / (RAND_MAX +1.0); + ps.push_back({x,y}); + } + sort(all(ps)); ps.erase(unique(all(ps)), ps.end()); + tick(); + split_tree T(ps); + cout << T.depth(T.root) << endl; + cout << n << " " << tick() << endl; + } +} + + +int main() { + //verify_intersectCC(); + //verify_three_point_circle(); + //verify_triangulate(); + //verify_convex_cut2(); + //verify_tangent(); + //verify_tangentCC(); + //verify_tangentCC2(); + //verify_intersect_area(); + //verify_closest_pair(); + //verify_half_plane_intersection(); + //verify_polar_angle(); + //verify_maximum_circle_cover(); + //verify_maximum_circle_cover2(); + //verify_rectangle_union(); + //verify_points_counter(); + //verify_circle_intersection_area(); + //verify_geometric_median(); + //verify_tangent_circles(); + //verify_maximum_points_line(); + //verify_arrangement(); + //verify_merge_segment(); + //AOJ1226(); + //AOJ2448(); + //AOJ1247(); + //verify_relative_neighborhood_graph(); + //verify_nearest_neighbor_structure(); + //verify_delaunay(); + //POJ2235(); + // verify_voronoi(); + //verify_is_congruence(); + //AOJ1514(); + //AOJ0273(); + //verify_farthest_pair(); + //ACAC002(); + //verify_compressed_quad_tree(); + //verify_split_tree(); + //verify_farthest_voronoi(); + //verify_convex_hull_discs(); +} From 68d7c6e53e0f143580989ba23e406c5844fce8af Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 30 Dec 2017 11:41:03 +0900 Subject: [PATCH 063/141] order maintenance data structure (dietz and sleator) --- data_structure/order_maintenance.cc | 122 ++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 data_structure/order_maintenance.cc diff --git a/data_structure/order_maintenance.cc b/data_structure/order_maintenance.cc new file mode 100644 index 0000000..4555199 --- /dev/null +++ b/data_structure/order_maintenance.cc @@ -0,0 +1,122 @@ +// +// Order Maintenance +// +// - create_node(): return new node x +// - insert(x, y): insert node y after node x +// - erase(x): erase node x from the list +// - order(x, y): return true if x is before y +// +// Running Time: +// worst case O(1) for create_node, erase, and order. +// amortized O(log n) for insert; very small constant. +// +// Reference: +// P. Dietz and D. Sleator (1987): +// "Two algorithms for maintaining order in a list". +// STOC. +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define fst first +#define snd second +#define all(c) (c).begin(), (c).end() + +using namespace std; + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +struct order_maintenance { + using label_type = unsigned long long; + using signed_label_type = long long; + const label_type M = ~((~label_type(0))>>1); + struct node { + node *prev = 0, *next = 0; + label_type label; // allows to contain at most sqrt(M) elements + } *head; + + order_maintenance() { + head = new node(); + head->next = head->prev = head; + } + label_type width(node *x, node *y) { + label_type ret = y->label - x->label; + if (ret - 1 >= M) ret += M; + return ret; + } + void insert(node *x, node *u) { + label_type label = x->label; + if (width(x, x->next) <= 1) { + node *mid = x->next, *end = mid->next; + label_type required = 3; + while (width(x, end) <= 4 * width(x, mid) && end != x) { + ++required; + end = end->next; + if (end == x) break; + ++required; + end = end->next; + mid = mid->next; + } + label_type gap = (x == end ? M : width(x, end)) / required; + label_type val = end->label; + while (1) { + if (end == head) val += M; + end = end->prev; + if (end == x) break; + val -= gap; + end->label = val; + } + } + u->label = label + width(x, x->next)/2; + u->next = x->next; + u->prev = x; + u->next->prev = u; + u->prev->next = u; + } + void erase(node *u) { + u->prev->next = u->next->prev; + u->next->prev = u->prev->next; + } + node *create_node() { + return new node; + } + bool order(node *x, node *y) { + return x->label < y->label; + } +}; + +int main() { + order_maintenance T; + int n = 1000000; + vector nodes(n); + vector order(n); + for (int i = 0; i < n; ++i) { + nodes[i] = T.create_node(); + order[i] = i; + } + random_shuffle(all(order)); + tick(); + T.insert(T.head, nodes[order[0]]); + for (int i = 1; i < n; ++i) { + //cout << i << endl; + T.insert(nodes[order[i-1]], nodes[order[i]]); + } + cout << tick() << endl; +} From 846d2dffcdc588c61e074988ac9220067fd8b187 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 30 Dec 2017 22:22:17 +0900 Subject: [PATCH 064/141] Union Find with Undo --- data_structure/undoable_union_find.cc | 120 ++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 data_structure/undoable_union_find.cc diff --git a/data_structure/undoable_union_find.cc b/data_structure/undoable_union_find.cc new file mode 100644 index 0000000..a2b0b3c --- /dev/null +++ b/data_structure/undoable_union_find.cc @@ -0,0 +1,120 @@ +// +// Undoable Union Find +// +// It can undo each unite operation. +// +// Naming: +// Data structures with undo operation is weaker than +// partially-persistence (accessible all older vers) and +// slightly stronger than semi-persistence (backtrackable). +// +#include +#include +#include +#include +#include +#include + +using namespace std; +#define fst first +#define snd second +#define all(c) begin(c), end(c) + +struct undoable_union_find { + vector p; + undoable_union_find(int n) : p(n, -1) { }; + vector> hist; + bool unite(int u, int v) { + if ((u = root(u)) == (v = root(v))) return false; + if (p[u] > p[v]) swap(u, v); + hist.push_back(make_tuple(u, v, p[v])); + p[u] += p[v]; p[v] = u; + return true; + } + void undo() { + int u, v, w; tie(u, v, w) = hist.back(); + hist.pop_back(); + p[v] = w; + p[u] -= p[v]; + } + bool find(int u, int v) { return root(u) == root(v); } + int root(int u) { for (; p[u] >= 0; u = p[u]); return u; } + int size(int u) { return -p[root(u)]; } +}; + +struct offline_dynamic_connectivity { + int n; + undoable_union_find uf; + offline_dynamic_connectivity(int n) : n(n), uf(n) { } + + typedef pair edge; + vector query; + vector ans; + map>> appear; + + void add_edge(int u, int v) { + if (u > v) swap(u, v); + appear[{u,v}].push_back({query.size(), 1<<30}); + } + void erase_edge(int u, int v) { + if (u > v) swap(u, v); + appear[{u,v}].back().snd = query.size(); + } + int is_connected(int u, int v) { + query.push_back({u,v}); + return query.size()-1; + } + + vector> es; + void insert(int l, int r, int k, int s, int t, edge e) { + s = max(s, l); t = min(r, t); + if (s >= t) return; + if (s == l && t == r) { + es[k].insert(e); + } else { + insert(l, (l+r)/2, 2*k+1, s, t, e); + insert((l+r)/2, r, 2*k+2, s, t, e); + if (es[2*k+1].count(e) && es[2*k+2].count(e)) { + es[2*k+1].erase(e); + es[2*k+2].erase(e); + es[k].insert(e); + } + } + } + void rec(int l, int r, int k) { + if (l >= r) return; + for (edge e: es[k]) uf.unite(e.fst, e.snd); + if (l+1 == r) { + ans[l] = uf.find(query[l].fst, query[l].snd); + } else { + rec(l, (l+r)/2, 2*k+1); + rec((l+r)/2, r, 2*k+2); + } + for (edge e: es[k]) uf.undo(); + } + void solve() { + int q = query.size(); + es.resize(4*q); + for (auto a: appear) + for (auto b: a.snd) + insert(0, q, 0, b.fst, b.snd, a.fst); + ans.assign(q, 0); + rec(0, q, 0); + } +}; + +int main() { + offline_dynamic_connectivity solver(3); + solver.is_connected(0,1); + solver.add_edge(0,1); + solver.is_connected(0,1); + solver.is_connected(1,2); + solver.add_edge(1,2); + solver.is_connected(0,2); + solver.erase_edge(0,1); + solver.is_connected(0,2); + solver.solve(); + for (int i = 0; i < solver.query.size(); ++i) { + cout << solver.query[i].fst << " " << solver.query[i].snd << " " << solver.ans[i] << endl; + } +} From bca7619d9c91f6b0e92c6f44c63a69d7146e187f Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 1 Jan 2018 01:41:43 +0900 Subject: [PATCH 065/141] Link-Cut Tree (simple) --- graph/link_cut_tree.cc | 148 ++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 76 deletions(-) diff --git a/graph/link_cut_tree.cc b/graph/link_cut_tree.cc index b1217eb..7b7bd6c 100644 --- a/graph/link_cut_tree.cc +++ b/graph/link_cut_tree.cc @@ -1,8 +1,11 @@ // -// Link Cut Tree +// Link Cut Tree (Slator-Tarjan) // // Decription: -// It maintains rooted forests with link/cut operations +// It maintains rooted arborescences with the following operations +// link(u,v) : add link from u to v +// cut(u) : cut link from u (to the root direction) +// lca(u,v) : least common ancestor of u and v // // Algorithm: // Classify links into solid and dashed. @@ -18,103 +21,96 @@ // D. D. Sleator and R. E. Tarjan (1983): // A Data Structure for Dynamic Trees. // Journal oF Computer and System Sciences, vol. 26, no. 3, pp. 362-391. +// +// Verified: AOJ Spaceships + #include #include #include +#include using namespace std; struct link_cut_tree { struct node { - int x, s; // value and sum - node *ch[2], *p; + node *child[2], *parent; }; - int sum(node *t) { return t ? t->s : 0; } - node *update(node *t) { - if (t) t->s = t->x + sum(t->ch[0]) + sum(t->ch[1]); - return t; - } - node *make_node(int x) { return new node({x, x, 0, 0, 0}); } - - int dir(node *t) { return t != t->p->ch[0]; } - bool is_root(node *t) { - return !t->p || (t->p->ch[0] != t && t->p->ch[1] != t); - } - void connect(node *p, node *t, int d) { - p->ch[d] = t; if (t) t->p = p; - update(p); + bool is_root(node *x) { + return !x->parent || (x->parent->child[0] != x + && x->parent->child[1] != x); } - void rot(node *t) { - node *p = t->p; - int d = dir(t); - if (!is_root(p)) connect(p->p, t, dir(p)); - else t->p = p->p; - connect(p, t->ch[!d], d); - connect(t, p, !d); + int dir(node *x) { return x->parent && x->parent->child[1] == x; } + void rot(node* t) { + node *p = t->parent, *g = p->parent; + int d = dir(t); + p->child[d] = t->child[!d]; + if (p->child[d]) p->child[d]->parent = p; + if (!is_root(p)) g->child[dir(p)] = t; + t->parent = g; + t->child[!d] = p; + p->parent = t; } - void splay(node *t) { - for (; !is_root(t); rot(t)) - if (!is_root(t->p)) rot(dir(t) == dir(t->p) ? t->p : t); + void splay(node *x) { + while (!is_root(x)) { + if (!is_root(x->parent)) { + if (dir(x) == dir(x->parent)) rot(x->parent); + else rot(x); + } + rot(x); + } } - node *expose(node *t) { - node *l = 0; - for (node *s = t; s; s = s->p) { - splay(s); - connect(s, l, 1); - l = s; + node *expose(node *x) { + node *r = 0; + for (node *p = x; p; p = p->parent) { + splay(p); + p->child[1] = r; + r = p; } - splay(t); - return l; + splay(x); + return r; } - void link(node *t, node *p) { - expose(t); - expose(p); - t->p = p; + + vector ns; + link_cut_tree(int n) : ns(n) { + for (int i = 0; i < n; ++i) + ns[i].child[0] = ns[i].child[1] = ns[i].parent = 0; } - void cut(node *t) { - expose(t); - t->ch[0] = t->ch[0]->p = 0; + void link(int x, int y) { + expose(&ns[x]); + expose(&ns[y]); + ns[y].child[1] = &ns[x]; + ns[x].parent = &ns[y]; } - node *lca(node *s, node *t) { - expose(s); - node *u = expose(t); - return !s->p ? 0 : u; + void cut(int x) { + expose(&ns[x]); + node *y = ns[x].child[0]; + ns[x].child[0] = y->parent = 0; } - int sum_to_root(node *t) { - expose(t); - return sum(t->ch[0]) + t->x; + int lca(int x, int y) { + expose(&ns[x]); + node *u = expose(&ns[y]); + return ns[x].parent ? u - &ns[0] : -1; } }; int main() { - link_cut_tree LCT; - int n, m; cin >> n >> m; - - vector a(n); - for (int i = 0; i < n; ++i) { - a[i] = LCT.make_node(i+1); - } + int n, q, t, a, b; + scanf("%d %d", &n, &q); - int u, v; - link_cut_tree::node *p; - for (int k = 0; k < m; ++k) { - int t; cin >> t; - switch (t) { - case 1: - cin >> u >> v; --u; --v; - LCT.link(a[u], a[v]); - break; - case 2: - cin >> u; --u; - LCT.cut(a[u]); - break; - case 3: - cin >> u >> v; --u; --v; - p = LCT.lca(a[u], a[v]); - if (!p) cout << "-1" << endl; - else cout << p->x << endl; - break; + link_cut_tree LCT(n); + for (int i = 0; i < q; ++i) { + scanf("%d", &t); + if (t == 1) { + scanf("%d %d", &a, &b); + LCT.link(a-1, b-1); + } else if (t == 2) { + scanf("%d", &a); + LCT.cut(a-1); + } else { + scanf("%d %d", &a, &b); + int c = LCT.lca(a-1, b-1); + printf("%d\n", c < 0 ? c : c+1); } } } From 68bf05a2ad3edd97267b1456600727ea6044fc18 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 1 Jan 2018 01:44:05 +0900 Subject: [PATCH 066/141] Link Cut Tree (simple) --- graph/link_cut_tree.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graph/link_cut_tree.cc b/graph/link_cut_tree.cc index 7b7bd6c..0e8fcb6 100644 --- a/graph/link_cut_tree.cc +++ b/graph/link_cut_tree.cc @@ -42,12 +42,12 @@ struct link_cut_tree { } int dir(node *x) { return x->parent && x->parent->child[1] == x; } void rot(node* t) { - node *p = t->parent, *g = p->parent; + node *p = t->parent; int d = dir(t); p->child[d] = t->child[!d]; if (p->child[d]) p->child[d]->parent = p; - if (!is_root(p)) g->child[dir(p)] = t; - t->parent = g; + if (!is_root(p)) p->parent->child[dir(p)] = t; + t->parent = p->parent; t->child[!d] = p; p->parent = t; } From e79e5af1490e5ff5e96ca8bfa5c81239a51c0aa6 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 2 Jan 2018 23:42:03 +0900 Subject: [PATCH 067/141] Union Find data structure --- data_structure/union_find.cc | 151 ++++++++++++++++++++++++++++++++--- 1 file changed, 142 insertions(+), 9 deletions(-) diff --git a/data_structure/union_find.cc b/data_structure/union_find.cc index 2cc999d..7e89276 100644 --- a/data_structure/union_find.cc +++ b/data_structure/union_find.cc @@ -1,17 +1,150 @@ +// +// Union Find Data Structure +// +// Description: +// An union-find data structure (aka. disjoint set data structure) +// maintains a disjoint sets and supports the following operations. +// - unite(u, v): merge sets containing u and v. +// - find(u, v) : return true if u and v are in the same set +// - size(u) : size of the set containing u. // -// Union Find data structure +// The weighted version additionally maintains the values for the +// elements and supports the following operations: +// - add(u, a) : value[u] += a +// - addSet(u, a): value[v] += a for v in set(u) +// - get(u) : return value[u] +// - getSet(u) : return sum(value[v] for v in set(u)) // +// Complexity: +// Amortized O(a(n)) for all operations. +// Here, a(n) is the inverse Ackermann function, which is +// less than five for a realistic size input. +// +// Verified: +// AOJ1330 http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1330 +// and other many problems. +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) -struct union_find { - vector p; - union_find(int n) : p(n, -1) { }; +struct UnionFind { + vector parent; // parent[root] is the negative of the size. + UnionFind(int n) : parent(n, -1) { }; bool unite(int u, int v) { - if ((u = root(u)) == (v = root(v))) return false; - if (p[u] > p[v]) swap(u, v); - p[u] += p[v]; p[v] = u; + u = root(u); v = root(v); + if (u == v) return false; + if (parent[u] > parent[v]) swap(u, v); + parent[u] += parent[v]; parent[v] += u; return true; } bool find(int u, int v) { return root(u) == root(v); } - int root(int u) { return p[u] < 0 ? u : p[u] = root(p[u]); } - int size(int u) { return -p[root(u)]; } + int root(int u) { return parent[u] < 0 ? u : parent[u] = root(parent[u]); } + int size(int u) { return -parent[root(u)]; } }; + +template +struct WeightedUnionFind { + struct Data { + int parent = -1; + T value = 0, delta = 0, total = 0; + }; + vector data; + WeightedUnionFind(int n) : data(n) { } + + void add(int u, T a) { + data[u].value += a; + data[root(u)].total += a; + } + void addSet(int u, T a) { + data[root(u)].delta += a; + data[root(u)].total -= data[root(u)].parent * a; + } + T get(int u) { + return data[u].value + root_(u).snd; + } + T getSet(int u) { + return data[root(u)].total; + } + bool unite(int u, int v) { + u = root(u); v = root(v); + if (u == v) return false; + if (data[u].parent > data[v].parent) swap(u, v); + data[u].parent += data[v].parent; + data[v].parent = u; + data[v].delta -= data[u].delta; + data[u].total += data[v].total; + return true; + } + pair root_(int u) { + if (data[u].parent < 0) return {u, data[u].delta}; + auto p = root_(data[u].parent); + p.snd += data[u].delta; + data[u].parent = p.fst; + data[u].delta = p.snd - data[p.fst].delta; + return p; + } + int root(int u) { return root_(u).fst; } + bool find(int u, int v) { + return root(u) == root(v); + } + int size(int u) { + return -data[root(u)].parent; + } +}; + +int test() { + int n = 5; + WeightedUnionFind uf(n); + for (int i = 0; i < n; ++i) { + uf.add(i, i); + } + uf.unite(2, 4); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } + cout << endl; + uf.unite(3, 4); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } + cout << endl; + uf.add(3,10); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } + cout << endl; + uf.addSet(4,5); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } +} + +void AOJ1330() { + for (int n, m; cin >> n >> m && n; ) { + WeightedUnionFind uf(n); + for (int i = 0; i < m; ++i) { + char c[2]; + int a, b; + scanf("%s %d %d", c, &a, &b); + --a; --b; + if (c[0] == '!') { + long long x; + scanf("%Ld", &x); + uf.addSet(b, uf.get(a)-uf.get(b)-x); + uf.unite(a, b); + } else { + if (uf.find(a, b)) { + printf("%Ld\n", uf.get(a)-uf.get(b)); + } else { + printf("UNKNOWN\n"); + } + } + } + } +} +int main() { AOJ1330(); } From 6c4a86dea5a487dbdd5fe96b3589d950e42c370d Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 2 Jan 2018 23:51:38 +0900 Subject: [PATCH 068/141] Union Find --- data_structure/union_find.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structure/union_find.cc b/data_structure/union_find.cc index 7e89276..6a56b5e 100644 --- a/data_structure/union_find.cc +++ b/data_structure/union_find.cc @@ -39,7 +39,7 @@ struct UnionFind { u = root(u); v = root(v); if (u == v) return false; if (parent[u] > parent[v]) swap(u, v); - parent[u] += parent[v]; parent[v] += u; + parent[u] += parent[v]; parent[v] = u; return true; } bool find(int u, int v) { return root(u) == root(v); } From bd586ff14ffb1065fac4ccf00a5989eb76d9edd2 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 2 Jan 2018 23:53:36 +0900 Subject: [PATCH 069/141] Union Find with Undo --- ...able_union_find.cc => !union_find_undo.cc} | 89 ++++++++++--------- 1 file changed, 46 insertions(+), 43 deletions(-) rename data_structure/{undoable_union_find.cc => !union_find_undo.cc} (51%) diff --git a/data_structure/undoable_union_find.cc b/data_structure/!union_find_undo.cc similarity index 51% rename from data_structure/undoable_union_find.cc rename to data_structure/!union_find_undo.cc index a2b0b3c..4aff857 100644 --- a/data_structure/undoable_union_find.cc +++ b/data_structure/!union_find_undo.cc @@ -20,81 +20,84 @@ using namespace std; #define snd second #define all(c) begin(c), end(c) -struct undoable_union_find { - vector p; - undoable_union_find(int n) : p(n, -1) { }; - vector> hist; + +struct UndoableUnionFind { + vector parent; + vector> history; + UndoableUnionFind(int n) : parent(n, -1) { }; bool unite(int u, int v) { - if ((u = root(u)) == (v = root(v))) return false; - if (p[u] > p[v]) swap(u, v); - hist.push_back(make_tuple(u, v, p[v])); - p[u] += p[v]; p[v] = u; + u = root(u); v = root(v); + if (u == v) return false; + if (parent[u] > parent[v]) swap(u, v); + history.push_back(make_tuple(u, v, parent[v])); + parent[u] += parent[v]; parent[v] = u; return true; } void undo() { - int u, v, w; tie(u, v, w) = hist.back(); - hist.pop_back(); - p[v] = w; - p[u] -= p[v]; + int u, v, w; + tie(u, v, w) = history.back(); + history.pop_back(); + parent[v] = w; + parent[u] -= parent[v]; } bool find(int u, int v) { return root(u) == root(v); } - int root(int u) { for (; p[u] >= 0; u = p[u]); return u; } - int size(int u) { return -p[root(u)]; } + int root(int u) { return parent[u] < 0 ? u : parent[u] = root(parent[u]); } + int size(int u) { return -parent[root(u)]; } }; -struct offline_dynamic_connectivity { + +struct OfflineDynamicConnectivity { int n; - undoable_union_find uf; - offline_dynamic_connectivity(int n) : n(n), uf(n) { } + UndoableUnionFind uf; + OfflineDynamicConnectivity(int n) : n(n), uf(n) { } - typedef pair edge; - vector query; + typedef pair Edge; + vector query; vector ans; - map>> appear; + map>> appear; - void add_edge(int u, int v) { + void addEdge(int u, int v) { if (u > v) swap(u, v); appear[{u,v}].push_back({query.size(), 1<<30}); } - void erase_edge(int u, int v) { + void eraseEdge(int u, int v) { if (u > v) swap(u, v); appear[{u,v}].back().snd = query.size(); } - int is_connected(int u, int v) { + int isConnected(int u, int v) { query.push_back({u,v}); return query.size()-1; } - - vector> es; - void insert(int l, int r, int k, int s, int t, edge e) { + vector> edges; + void insert(int l, int r, int k, int s, int t, Edge e) { s = max(s, l); t = min(r, t); if (s >= t) return; if (s == l && t == r) { - es[k].insert(e); + edges[k].insert(e); } else { insert(l, (l+r)/2, 2*k+1, s, t, e); insert((l+r)/2, r, 2*k+2, s, t, e); - if (es[2*k+1].count(e) && es[2*k+2].count(e)) { - es[2*k+1].erase(e); - es[2*k+2].erase(e); - es[k].insert(e); + if (edges[2*k+1].count(e) && edges[2*k+2].count(e)) { + edges[2*k+1].erase(e); + edges[2*k+2].erase(e); + edges[k].insert(e); } } } void rec(int l, int r, int k) { if (l >= r) return; - for (edge e: es[k]) uf.unite(e.fst, e.snd); + for (Edge e: edges[k]) uf.unite(e.fst, e.snd); if (l+1 == r) { ans[l] = uf.find(query[l].fst, query[l].snd); } else { rec(l, (l+r)/2, 2*k+1); rec((l+r)/2, r, 2*k+2); } - for (edge e: es[k]) uf.undo(); + for (Edge e: edges[k]) uf.undo(); } void solve() { int q = query.size(); - es.resize(4*q); + edges.resize(4*q); for (auto a: appear) for (auto b: a.snd) insert(0, q, 0, b.fst, b.snd, a.fst); @@ -104,15 +107,15 @@ struct offline_dynamic_connectivity { }; int main() { - offline_dynamic_connectivity solver(3); - solver.is_connected(0,1); - solver.add_edge(0,1); - solver.is_connected(0,1); - solver.is_connected(1,2); - solver.add_edge(1,2); - solver.is_connected(0,2); - solver.erase_edge(0,1); - solver.is_connected(0,2); + OfflineDynamicConnectivity solver(3); + solver.isConnected(0,1); + solver.addEdge(0,1); + solver.isConnected(0,1); + solver.isConnected(1,2); + solver.addEdge(1,2); + solver.isConnected(0,2); + solver.eraseEdge(0,1); + solver.isConnected(0,2); solver.solve(); for (int i = 0; i < solver.query.size(); ++i) { cout << solver.query[i].fst << " " << solver.query[i].snd << " " << solver.ans[i] << endl; From f704c1cd254859087265d99c38f870ae7feaabe6 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 3 Jan 2018 00:09:24 +0900 Subject: [PATCH 070/141] Cartesian Tree --- data_structure/cartesian_tree.cc | 106 +++++++++++++++---------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/data_structure/cartesian_tree.cc b/data_structure/cartesian_tree.cc index 45a40c8..7efa2b2 100644 --- a/data_structure/cartesian_tree.cc +++ b/data_structure/cartesian_tree.cc @@ -2,35 +2,28 @@ // Cartesian Tree // // Description: -// For a given sequence x, the Cartesian tree is recursively +// For a given sequence xs, the Cartesian tree is recursively // defined as follows: -// - root is the minimum in x. -// - the left child is the Cartesian tree for the the left of the min., -// and the right child is the Cartesian tree for the right of the min. -// -// Algorithm: -// Left-to-right construction. -// -// Applications: -// In order traversal gives the original sequence. -// Sorting can be performed in O(n log k) -// LCA of two element gives RMQ in original sequence. -// -// Complexity: -// construction: O(n) -// sort: O(n log k) by using priority queue. -// offline RMQ: O(n + q) by Tarjan's offline LCA. +// - the root is the minimum in xs. +// - the left child is the Cartesian tree for the the left segment, +// and the right child is the Cartesian tree for the right segment. +// It is constructed in O(n) time by the left-to-right traversal. // +// By using the Cartesian tree, we can solve +// - Sorting in O(n log k) time, where k is the number of consecutive +// sorted subsegments. +// - LCA(i,j) = RMQ(i,j). Thus, by using the Tarjan's Offline LCA, +// we can solve m RMQs in O(m a(n)) time. +// // Verified: -// SPOJ11772, SPOJ1005604 for RMQ. -// +// SPOJ RPLN: http://www.spoj.com/problems/RPLN/ +// // References: // C. Levcopoulos and O. Petersson (1989): // Heapsort - Adapted for Presorted Files. // in Proceedings of the Workshop on Algorithms and Data Structures, // pp. 499-509. - #include #include #include @@ -45,76 +38,83 @@ using namespace std; #define all(c) ((c).begin()), ((c).end()) template -struct cartesian_tree { +struct CartesianTree { int n, root; - vector x; - vector l, r, p; - cartesian_tree(const vector &x) - : n(x.size()), x(x), l(n,-1), r(n,-1), p(n,-1) { + vector xs; + struct Node { + int left = -1, right = -1, parent = -1; + }; + vector node; + CartesianTree(const vector &xs) : n(xs.size()), xs(xs), node(n) { root = 0; for (int i = 1; i < n; ++i) { int j = i-1; - while (p[j] >=0 && x[i] < x[j]) j = p[j]; - if (x[i] < x[j]) { - p[j] = i; - l[i] = j; + while (node[j].parent >=0 && xs[i] < xs[j]) + j = node[j].parent; + if (xs[i] < xs[j]) { + node[j].parent = i; + node[i].left = j; root = i; } else { - if (r[j] >= 0) p[r[j]] = i; - l[i] = r[j]; - p[i] = j; - r[j] = i; + if (node[j].right >= 0) node[node[j].right].parent = i; + node[i].left = node[j].right; + node[i].parent = j; + node[j].right = i; } } } // In-order traverse gives an original sequence void traverse(int t, int tab = 0) { if (t < 0) return; - traverse(l[t], tab + 2); + traverse(node[t].left, tab + 2); for (int i = 0; i < tab; ++i) cout << " "; - cout << x[t] << endl; - traverse(r[t], tab + 2); + cout << xs[t] << endl; + traverse(node[t].right, tab + 2); } void traverse() { traverse(root); } // Sorting in O(n log k) by Levcopoulos-Petersson void sort() { - auto comp = [&](int i, int j) { return x[i] > x[j]; }; + auto comp = [&](int i, int j) { return xs[i] > xs[j]; }; priority_queue, decltype(comp)> que(comp); que.push(root); while (!que.empty()) { int t = que.top(); que.pop(); - cout << x[t] << " "; - if (l[t] >= 0) que.push(l[t]); - if (r[t] >= 0) que.push(r[t]); + cout << xs[t] << " "; + if (node[t].left >= 0) que.push(node[t].left); + if (node[t].right >= 0) que.push(node[t].right); } cout << endl; } - struct union_find { - vector p; - union_find(int n) : p(n, -1) { }; + struct UnionFind { + vector parent; // parent[root] is the negative of the size. + UnionFind(int n) : parent(n, -1) { }; bool unite(int u, int v) { - if ((u = root(u)) == (v = root(v))) return false; - if (p[u] > p[v]) swap(u, v); - p[u] += p[v]; p[v] = u; + u = root(u); v = root(v); + if (u == v) return false; + if (parent[u] > parent[v]) swap(u, v); + parent[u] += parent[v]; parent[v] = u; return true; } - int root(int u) { return p[u] < 0 ? u : p[u] = root(p[u]); } + bool find(int u, int v) { return root(u) == root(v); } + int root(int u) { return parent[u] < 0 ? u : parent[u] = root(parent[u]); } + int size(int u) { return -parent[root(u)]; } }; + struct query { int u, v, a; }; - void range_min_queries(vector &queries) { + void rangeMinQueries(vector &queries) { vector> Q(n); for (auto &q: queries) { Q[q.u].push_back(&q); Q[q.v].push_back(&q); } - union_find uf(n); + UnionFind uf(n); vector anc(n), color(n); iota(all(anc), 0); function rec = [&](int u) { - for (int c: {l[u], r[u]}) { + for (int c: {node[u].left, node[u].right}) { if (c < 0) continue; rec(c); uf.unite(c, u); @@ -140,14 +140,14 @@ int main() { vector x(n); for (int i = 0; i < n; ++i) scanf("%d", &x[i]); - cartesian_tree T(x); + CartesianTree T(x); - vector::query> qs(q); + vector::query> qs(q); for (int i = 0; i < q; ++i) { scanf("%d %d", &qs[i].u, &qs[i].v); --qs[i].u; --qs[i].v; } - T.range_min_queries(qs); + T.rangeMinQueries(qs); for (auto q: qs) printf("%d\n", x[q.a]); } From 78ff9912b30bc6bdc1b52e576c55f77260add11b Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 3 Jan 2018 16:12:08 +0900 Subject: [PATCH 071/141] Partially Persistent Union Find --- .../partially_persistent_union_find.cc | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 data_structure/partially_persistent_union_find.cc diff --git a/data_structure/partially_persistent_union_find.cc b/data_structure/partially_persistent_union_find.cc new file mode 100644 index 0000000..1375395 --- /dev/null +++ b/data_structure/partially_persistent_union_find.cc @@ -0,0 +1,77 @@ +// +// Partially Persistent Union Find +// +// Description: +// It is a persistent version of union find data structure. +// It allows us to apply "find" to the all versions and +// "unite" to the latest version. +// +// Complexity: +// O(log n) for each query. +// +// Verified: +// CODE THANKS FESTIVAL 2017, Union Set: +// https://code-thanks-festival-2017-open.contest.atcoder.jp/tasks/code_thanks_festival_2017_h +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +using namespace std; + +struct PartiallyPersistentUnionFind { + vector>> parent; // (parent index, modified time) + int now = 0; // time = 0 is the initial state + PartiallyPersistentUnionFind(int n) : parent(n, {{-1,0}}) { } + bool unite(int u, int v) { + ++now; + u = root(u, now); v = root(v, now); + if (u == v) return false; + if (parent[u].back().fst > parent[v].back().fst) swap(u, v); + parent[u].push_back({parent[u].back().fst+parent[v].back().fst, now}); + parent[v].push_back({u, now}); + return true; + } + bool find(int u, int v, int t) { return root(u, t) == root(v, t); } + int root(int u, int t) { + if (parent[u].back().fst >= 0 && parent[u].back().snd <= t) + return root(parent[u].back().fst, t); + return u; + } + int size(int u, int t) { + u = root(u, t); + int lo = 0, hi = parent[u].size(); + while (lo + 1 < hi) { + int mi = (lo + hi) / 2; + if (parent[u][mi].snd <= t) lo = mi; + else hi = mi; + } + return -parent[u][lo].fst; + } +}; + +int main() { + int n, m, q, a, b; + scanf("%d %d", &n, &m); + + PartiallyPersistentUnionFind uf(n); + for (int i = 0; i < m; ++i) { + scanf("%d %d", &a, &b); --a; --b; + uf.unite(a, b); + } + scanf("%d", &q); + for (int i = 0; i < q; ++i) { + scanf("%d %d", &a, &b); --a; --b; + int lo = 0, hi = uf.now+1; + while (lo+1 < hi) { + int mi = (lo + hi) / 2; + if (uf.find(a, b, mi)) hi = mi; + else lo = mi; + } + if (hi == uf.now+1) printf("-1\n"); + else printf("%d\n", hi); + } +} From 3c0dc8722b025f2db8d44eb70ff156a682670eeb Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 3 Jan 2018 16:12:37 +0900 Subject: [PATCH 072/141] Union Find with Undo --- data_structure/{!union_find_undo.cc => union_find_undo.cc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data_structure/{!union_find_undo.cc => union_find_undo.cc} (100%) diff --git a/data_structure/!union_find_undo.cc b/data_structure/union_find_undo.cc similarity index 100% rename from data_structure/!union_find_undo.cc rename to data_structure/union_find_undo.cc From 628b02807e0fdaa011f7144286311138474a22c9 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 3 Jan 2018 18:54:18 +0900 Subject: [PATCH 073/141] Retroactive Queue --- data_structure/retroactive_queue.cc | 169 ++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 data_structure/retroactive_queue.cc diff --git a/data_structure/retroactive_queue.cc b/data_structure/retroactive_queue.cc new file mode 100644 index 0000000..ca63da9 --- /dev/null +++ b/data_structure/retroactive_queue.cc @@ -0,0 +1,169 @@ +// +// Fully Retroactive Queue +// +// Description: +// It maintains a list of actions ("push" and "pop"). +// We can insert/erase the actions and ask status ("front") in +// any position of the list. +// +// To implement this structure, we maintain the list by a BST +// and keep track the number of pushs/pops in each position +// by using the range addition and range minimum. +// +// Complexity: +// O(n log n). +// +// References: +// E. Demaine, J. Iacono, and S. Langerman (2007): +// "Retroactive data structures". ACM Transactions of Algorithms, +// vol.3, no.2, pp.1--21. +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +template +struct RetroactiveQueue { + struct Node { // Splay Tree + int type; // 0: none, 1: push, 2: pop + T value; + Node *child[2], *parent; + int a_push, d_push, a_pop, d_pop, min_remain; + } *head; + int remain(Node *x) { + return !x ? 0 : x->a_push + x->d_push - x->a_pop - x->d_pop; + } + RetroactiveQueue() : head(new Node({0})) { } + Node *update(Node *x) { + if (!x) return x; + x->min_remain = remain(x); + for (int i: {0, 1}) + if (x->child[i]) + x->min_remain = min(x->min_remain, x->child[i]->min_remain); + return x; + } + Node *pushdown(Node *x) { + if (!x) return x; + for (int i: {0, 1}) { + if (x->child[i]) { + x->child[i]->d_push += x->d_push; + x->child[i]->d_pop += x->d_pop; + } + } + x->a_push += x->d_push; + x->a_pop += x->d_pop; + x->d_push = x->d_pop = 0; + return x; + } + int dir(Node *x) { return x->parent && x->parent->child[1] == x; } + void link(Node *x, Node *y, int d) { + if (x) x->child[d] = y; + if (y) y->parent = x; + } + void rot(Node *x) { + int d = dir(x); + Node *p = x->parent; + pushdown(p->parent); pushdown(p); pushdown(x); + link(p->parent, x, dir(p)); + link(p, x->child[!d], d); + link(x, p, !d); + update(p); update(x); + } + void splay(Node *x) { + if (!x) return; + while (x->parent) { + if (x->parent->parent) { + if (dir(x) == dir(x->parent)) rot(x->parent); + else rot(x); + } + rot(x); + } + pushdown(x); + } + Node *insert(Node *x, Node *y) { + splay(x); + y->child[0] = x; + x->parent = y; + y->child[1] = x->child[1]; + x->child[1] = 0; + if (y->child[1]) { + y->child[1]->parent = y; + if (y->type == 1) y->child[1]->d_push += 1; + else if (y->type == 2) y->child[1]->d_pop += 1; + } + y->a_push = x->a_push + x->d_push + (y->type & 1); + y->a_pop = x->a_pop + x->d_pop + (y->type >> 1); + update(y->child[0]); + update(y->child[1]); + update(y); + return y; + } + Node *insert_push(Node *x, T a) { return insert(x, new Node({1, a})); } + Node *insert_pop(Node *x) { return insert(x, new Node({2})); } + Node *erase(Node *x) { + splay(x); + Node *y = x->child[1]; + if (!y) { + x = x->child[0]; + x->parent = 0; + return x; + } + if (x->type == 1) y->d_push -= 1; + else if (x->type == 2) y->d_pop -= 1; + y->parent = 0; + update(y); + while (y->child[0]) y = y->child[0]; + splay(y); + y->child[0] = x->child[0]; + if (y->child[0]) y->child[0]->parent = y; + update(y->child[0]); + update(y); + return y; + } + bool valid(Node *x) { splay(x); return x->min_remain >= 0; } + T front(Node *x) { + splay(x); + int k = x->a_pop + x->d_pop; + for (Node *y = x; y; ) { + pushdown(y); + if (y->a_push > k) { + x = y; + y = y->child[0]; + } else { + y = y->child[1]; + } + } + return x->value; + } + + + void display() { + splay(head); + display(head, 0); + } + void display(Node *x, int tab = 0) { + if (!x) return; + display(x->child[0], tab+2); + cout << string(tab, ' ') << x->type << " " << x->value << " " << x->a_push << " " << x->d_push << " " << x->a_pop << " " << x->d_pop << " " << x->min_remain << endl; + display(x->child[1], tab+2); + } +}; + +int main() { + RetroactiveQueue que; + auto i1 = que.insert_push(que.head, 10); + auto i2 = que.insert_push(i1, 20); + auto i3 = que.insert_push(i2, 30); + auto i4 = que.insert_pop(i3); + //auto i5 = que.insert_pop(i2); + que.erase(i1); + que.display(); + cout << que.front(i1) << endl; + cout << que.front(i2) << endl; + cout << que.front(i3) << endl; + cout << que.front(i4) << endl; +} From 53a285936e7419c0848903a607036f679d6cde90 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 3 Jan 2018 20:18:44 +0900 Subject: [PATCH 074/141] Initializable Array --- data_structure/initializable_array.cc | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 data_structure/initializable_array.cc diff --git a/data_structure/initializable_array.cc b/data_structure/initializable_array.cc new file mode 100644 index 0000000..37c45a3 --- /dev/null +++ b/data_structure/initializable_array.cc @@ -0,0 +1,66 @@ +// +// Initializable Array +// +// Description: +// It allows the following operations in O(1) time. +// - init(a): initialize xs[i] = a for all i +// - xs[i]: return xs[i] +// - set(i, a): set xs[i] = a +// The important operation is "init", which usually +// requires O(n) time. By maintaining timestamps, +// we can "emulate" the initialization. +// +// Complexity: +// O(1). +// +// References: +// J. Bentley (1986): Programming pearls. Addison-Wesley. +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +template +struct InitializableArray { + T initv, *value; + size_t b, *from, *to; + InitializableArray(int n) { + value = new T[n]; + from = new size_t[n]; + to = new size_t[n]; + } + bool chain(int i) { + int j = from[i]; + return j < b && to[j] == i; + } + void init(T a) { + initv = a; + b = 0; + } + T operator[](int i) { + return chain(i) ? value[i] : initv; + } + void set(int i, T a) { + if (!chain(i)) { + from[i] = b; + to[b++] = i; + } + value[i] = a; + } +}; + +int main() { + InitializableArray a(3); + cout << a.value[0] << endl; + a.init(0); + a.init(2); + a.set(1, 5); + cout << a[0] << endl; + cout << a[1] << endl; + cout << a[2] << endl; + a.set(2, 3); + a.init(0); +} From 69a6a4514b348ae356b9bd0e9285f5442150314c Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 5 Jan 2018 23:27:10 +0900 Subject: [PATCH 075/141] Continued Fraction --- math/continued_fraction.cc | 176 +++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 math/continued_fraction.cc diff --git a/math/continued_fraction.cc b/math/continued_fraction.cc new file mode 100644 index 0000000..2a34d84 --- /dev/null +++ b/math/continued_fraction.cc @@ -0,0 +1,176 @@ +// +// Continued Fraction +// +// Description: +// see https://perl.plover.com/yak/cftalk/ +// +// Gosper's algorithm +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Int = long long; +struct Generator { + using Pointer = shared_ptr; + virtual Int value() = 0; + virtual Pointer next() = 0; +}; + +// (a x + b)/(c x + d) +struct HoloGen : Generator { + Int a, b, c, d; + Pointer x; + HoloGen(Pointer x, Int a, Int b, Int c, Int d) : x(x), a(a), b(b), c(c), d(d) { } + void normalize() { + while (1) { + if (c == 0 && d == 0) break; + double b_ac = (double)a/c, b_bd = (double)b/d; + if ((Int)b_ac == (Int)b_bd) break; + if (!x) { + tie(a,b,c,d) = make_tuple(a,a,c,c); + } else { + Int p = x->value(); x = x->next(); + tie(a,b,c,d) = make_tuple(a*p+b,a,c*p+d,c); + } + } + } + virtual Int value() { normalize(); return a/c; } + virtual Pointer next() { + Int r = value(); + if (a-c*r == 0 && b-d*r == 0) return 0; + return Pointer(new HoloGen(x,c,d,a-c*r,b-d*r)); + } +}; +// (a x y + b x + c y + d)/(e x y + f x + g y + h) +struct ArithGen : Generator { + Int a, b, c, d, e, f, g, h; + Pointer x, y; + ArithGen(Pointer x, Pointer y, Int a, Int b, Int c, Int d, Int e, Int f, Int g, Int h) : x(x), y(y), a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) { } + void normalize() { + while (1) { + if (e == 0 && f == 0 && g == 0 && h == 0) break; + double b_ae = (double)a/e, b_cg = (double)c/g, + b_bf = (double)b/f, b_dh = (double)d/h; + if ((Int)b_ae == (Int)b_cg && + (Int)b_cg == (Int)b_bf && + (Int)b_bf == (Int)b_dh) break; + auto idiff = [&](double a, double b) { + if (isinf(a) && isinf(b)) return 0.0; + if (isinf(a) || isinf(b)) return 1.0/0.0; + return fabs(a - b); + }; + if (max(idiff(b_ae, b_cg), idiff(b_bf, b_dh)) + > max(idiff(b_ae, b_bf), idiff(b_cg, b_dh))) { + if (!x) { + tie(a,b,c,d,e,f,g,h) = make_tuple(a,b,a,b,e,f,e,f); + } else { + Int p = x->value(); x = x->next(); + tie(a,b,c,d,e,f,g,h) = make_tuple(a*p+c,b*p+d,a,b,e*p+g,f*p+h,e,f); + } + } else { + if (!y) { + tie(a,b,c,d,e,f,g,h) = make_tuple(a,a,c,c,e,e,g,g); + } else { + Int p = y->value(); y = y->next(); + tie(a,b,c,d,e,f,g,h) = make_tuple(a*p+b,a,c*p+d,c,e*p+f,e,g*p+h,g); + } + } + } + } + virtual Int value() { normalize(); return a/e; } + virtual Pointer next() { + Int r = value(); + if (a-e*r == 0 && b-f*r == 0 && c-g*r == 0 && d-h*r == 0) return 0; + return Pointer(new ArithGen(x,y,e,f,g,h,a-e*r,b-f*r,c-g*r,d-h*r)); + } +}; +struct ContinuedFraction { + using Pointer = shared_ptr; + Pointer head; + ContinuedFraction(Pointer head) : head(head) { } + double toReal() { + Pointer run = head; + function eval = [&](Pointer run, int depth) { + if (!run) return 1.0/0.0; + return run->value() + 1.0 / eval(run->next(), depth-1); + }; + return eval(head, 20); + } +}; +ContinuedFraction operator+(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 0, 1, 1, 0, 0, 0, 0, 1))); +} +ContinuedFraction operator-(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 0, 1, -1, 0, 0, 0, 0, 1))); +} +ContinuedFraction operator*(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 1, 0, 0, 0, 0, 0, 0, 1))); +} +ContinuedFraction operator/(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 0, 1, 0, 0, 0, 0, 1, 0))); +} +ContinuedFraction operator*(ContinuedFraction x, Int a) { + return ContinuedFraction(ContinuedFraction::Pointer( + new HoloGen(x.head, a, 0, 0, 1))); +} + +int compare(ContinuedFraction x, ContinuedFraction y) { + auto i = x.head, j = y.head; + while (1) { + if (!i && !j) return 0; + if (!j || i->value() < j->value()) return -1; + if (!i || i->value() > j->value()) return +1; + tie(i, j) = make_tuple(j->next(), i->next()); + } +} +bool operator==(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) == 0; } +bool operator!=(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) != 0; } +bool operator<=(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) <= 0; } +bool operator>=(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) >= 0; } +bool operator<(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) < 0; } +bool operator>(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) > 0; } + +struct Rational : ContinuedFraction { + struct RationalGen : Generator { + Int num, den; + RationalGen(Int num, Int den) : num(num), den(den) { } + virtual Int value() { + return num / den - (num < 0); + } + virtual Pointer next() { + if (num - value() * den == 0) return 0; + return Pointer(new RationalGen(den, num - value() * den)); + } + }; + Rational(Int a, Int b) : + ContinuedFraction(Pointer(new RationalGen(a, b))) { } +}; +struct NapierGenerator : Generator { + int i; + NapierGenerator(int i = 0) : i(i) { } + virtual Int value() { + if (i == 0) return 2; + if (i % 3 == 2) return 2 * (i/3) + 2; + return 1; + } + virtual Pointer next() { + return Pointer(new NapierGenerator(value())); + } +}; +ContinuedFraction e(ContinuedFraction::Pointer(new NapierGenerator(0))); + + + +int main() { + ContinuedFraction x = Rational(-8, 11), y = Rational(-1, 2); + cout << compare(x, y) << endl; + cout << x.toReal() << endl; +} From 208bcfd781e9c37aedee117ce45d5a4a5bab5fa1 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 5 Jan 2018 23:27:52 +0900 Subject: [PATCH 076/141] Rational Type --- math/rational.cc | 157 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 math/rational.cc diff --git a/math/rational.cc b/math/rational.cc new file mode 100644 index 0000000..ad41fc4 --- /dev/null +++ b/math/rational.cc @@ -0,0 +1,157 @@ +// +// Rational Type +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Int = long long; +struct Rational { + Int num, den; // x = num/den + + static Int gcd(Int a, Int b) { + for (; a; swap(a, b %= a)); + return b; + } + Rational(Int a = 0) : num(a), den(1) { } + Rational(Int a, Int b, bool do_normalize = false) : num(a), den(b) { + if (do_normalize) { + auto g = gcd(num, den); + num /= g; den /= g; + if (den < 0) { num = -num; den = -den; } + } + } + static Rational inf() { return Rational(1,0); } + + Rational inv() const { + if (num < 0) return {-den, -num}; + else return { den, num}; + } + Rational operator+() const { return *this; } + Rational operator-() const { return Rational(-num,den); } + Rational &operator+=(Rational x) { + auto g = gcd(den, x.den); + num = num*(x.den/g) + (den/g)*x.num; + den = den*(x.den/g); + return *this; + } + Rational &operator*=(Rational x) { + auto g = gcd(num, x.den), h = gcd(den, x.num); + num = (num/g)*(x.num/h); + den = (den/h)*(x.den/g); + if (den < 0) { num = -num; den = -den; } + return *this; + } + Rational &operator-=(Rational x) { return *this += -x; } + Rational &operator/=(Rational x) { return *this *= x.inv(); } +}; +Rational operator+(Rational x, Rational y) { return x += y; } +Rational operator-(Rational x, Rational y) { return x -= y; } +Rational operator*(Rational x, Rational y) { return x *= y; } +Rational operator/(Rational x, Rational y) { return x /= y; } +int compare(Rational x, Rational y) { // sign(x-y) + if (x.num == 0) return (y.num < 0) - (y.num > 0); + if (x.num < 0) return y.num >= 0 ? -1 : compare(-y, -x); + if (y.num <= 0) return 1; + while (x.den != 0 && y.den != 0) { + auto a = x.num/x.den, b = y.num/y.den; + if (a != b) return a - b; + swap(x.num -= a*x.den, x.den); + swap(y.num -= b*y.den, y.den); + swap(x, y); + } + if (x.den != 0) return -y.num; + if (y.den != 0) return x.num; + return x.num - y.num; +} +bool operator==(Rational x, Rational y) { return compare(x,y)==0; } +bool operator!=(Rational x, Rational y) { return compare(x,y)!=0; } +bool operator<=(Rational x, Rational y) { return compare(x,y)<=0; } +bool operator>=(Rational x, Rational y) { return compare(x,y)>=0; } +bool operator<(Rational x, Rational y) { return compare(x,y)<0; } +bool operator>(Rational x, Rational y) { return compare(x,y)>0; } + +ostream &operator<<(ostream &os, Rational x) { os<= 0; --i) + swap(num, den += as[i] * num); + if (abs(num) >= 1e9 || abs(den) >= 1e9) { + num = num_; den = den_; + break; // overflow; backup and forgive + } + auto error = fabs(Real(num)/den - a); + b -= as[k]; + if (b == 0 || error < 1e-16) break; + b = 1 / b; + } + if (den < 0) { num = -num; den = -den; } + return Rational(num, den, false); +} + + +/* +Rational approx(Rational::Real a) { + Rational::Int num = 1, den = 0; + Rational::Int as[30] = {0}; + auto b = a; + for (int k = 0; k < 30; ++k) { + as[k] = round(b); + auto numk = num, denk = den; + for (int i = k; i >= 0; --i) + swap(numk, denk += as[i] * numk); + if (abs(numk) >= 1e9 || abs(denk) >= 1e9) break; // overflow + auto error = fabs(Real(numk)/denk - a); + if (error < 1e-9) { + num = numk; den = denk; + break; + } + b -= as[k]; + if (b == 0) break; + b = 1 / b; + } + return Rational(num, den); +} +*/ +void verify_compare() { + srand( time(0) ); + for (int iter = 0; iter < 100000; ++iter) { + cout << iter << endl; + Rational x(rand()%100, 1 + rand()%100); + Rational y(rand()%100, 1 + rand()%100); + assert( (x < y) == (-y < -x) ); + assert( x == x ); + assert( -x == -x ); + assert( (x == y) == (-x == -y) ); + assert( (x != y) == (-x != -y) ); + if (x != Rational(0,1)) assert( (y + x) != (y - x) ); + if (x > Rational(0,1)) assert( (y-x) < (y+x) ); + if (x > Rational(0,1)) assert( (-y-x) < (-y+x) ); + } +} + +int main() { + // 0/1 < 1/1 + /* + Rational x(2,1), y(3,1); + cout << x + y << endl; + */ + /* + Rational x = atan(sqrt(Rational(1,2))); + cout << x << endl; + printf("%.12f\n%.12f\n", (double)x, atan(sqrt(1.0/2.0))); + */ + verify_compare(); +} From bd5aae04b8d8a1c05a894f6223e8df50cdba23a2 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 10:46:25 +0900 Subject: [PATCH 077/141] Bentley-Ottman's Segment Arrangement in O((n+k) log n) --- geometry/segment_arrangement.cc | 340 ++++++++++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 geometry/segment_arrangement.cc diff --git a/geometry/segment_arrangement.cc b/geometry/segment_arrangement.cc new file mode 100644 index 0000000..c3233e6 --- /dev/null +++ b/geometry/segment_arrangement.cc @@ -0,0 +1,340 @@ +// +// Segment Arrangement (Bentley-Ottman's Plane-Sweep) +// +// Description: +// Given a set of segments, it finds the all intersections of the +// segments and construct the graph structure. By the plane-sweep +// with the balanced binary search tree, it runs in O(k log n) +// time, where k is the size of output. +// +// Complexity: +// O(k log n), where k is the size of input. +// +// References: +// CGAA +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Real = double; +const Real EPS = 1e-8; +int sign(Real x) { return (x > EPS) - (x < -EPS); } +struct Point { + Real x, y; + Point &operator+=(Point p) { x += p.x; y += p.y; return *this; } + Point &operator*=(Real a) { x *= a; y *= a; return *this; } + Point operator+() const { return {+x, +y}; } + Point operator-() const { return {-x, -y}; } + + Point &operator-=(Point p) { return *this += -p; } + Point &operator/=(Real a) { return *this *= 1/a; } +}; +Point operator+(Point p, Point q) { return p += q; } +Point operator-(Point p, Point q) { return p -= q; } +Point operator*(Real a, Point p) { return p *= a; } +Point operator*(Point p, Real a) { return p *= a; } +Point operator/(Point p, Real a) { return p /= a; } + +int compare(Point p, Point q) { + int s = sign(p.x - q.x); + return s ? s : sign(p.y - q.y); +} +bool operator==(Point p, Point q) { return compare(p,q)==0; } +bool operator!=(Point p, Point q) { return compare(p,q)!=0; } +bool operator<=(Point p, Point q) { return compare(p,q)<=0; } +bool operator>=(Point p, Point q) { return compare(p,q)>=0; } +bool operator<(Point p, Point q) { return compare(p,q)<0; } +bool operator>(Point p, Point q) { return compare(p,q)>0; } + +Real dot(Point p, Point q) { return p.x*q.x+p.y*q.y; } +Real cross(Point p, Point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +Real norm2(Point p) { return dot(p,p); } +Point orth(Point p) { return {-p.y, p.x}; } +Real norm(Point p) { return sqrt(dot(p,p)); } +Real arg(Point p) { return atan2(p.y, p.x); } +Real arg(Point p, Point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, Point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const Point &p) { os<<"("< intersect(Segment s, Segment t) { + auto a = cross(s.q - s.p, t.q - t.p); + auto b = cross(t.p - s.p, t.q - t.p); + auto c = cross(s.q - s.p, s.p - t.p); + if (a < 0) { a = -a; b = -b; c = -c; } + if (sign(b) < 0 || sign(a-b) < 0 || + sign(c) < 0 || sign(a-c) < 0) return {}; // disjoint + if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing + vector ps; // same line + auto insert_if_possible = [&](Point p) { + for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return; + ps.push_back(p); + }; + if (sign(dot(s.p-t.p, s.q-t.p)) <= 0) insert_if_possible(t.p); + if (sign(dot(s.p-t.q, s.q-t.q)) <= 0) insert_if_possible(t.q); + if (sign(dot(t.p-s.p, t.q-s.p)) <= 0) insert_if_possible(s.p); + if (sign(dot(t.p-s.q, t.q-s.q)) <= 0) insert_if_possible(s.q); + return ps; +} + +struct DoublyConnectedEdgeList { + struct Vertex { int edge; }; // incident + struct Edge { int vertex, twin, prev, next, face; }; // origin, twin, incident list, left face + struct Face { int edge; }; // any incident face + vector point; + vector vertex; + vector edge; + vector face; + int newVertex(Point p, int e = -1) { + point.push_back(p); + vertex.push_back({e}); + return vertex.size()-1; + } + int newEdge(int vertex = -1) { + edge.push_back({vertex, -1, -1, -1, -1}); + return edge.size()-1; + } + void completeFaces() { + face.clear(); + for (int e = 0; e < edge.size(); ++e) edge[e].face = -1; + for (int e = 0; e < edge.size(); ++e) { + if (edge[e].face >= 0) continue; + int f = face.size(); + face.push_back({e}); + int x = e; + do { + edge[x].face = f; + x = edge[edge[x].twin].prev; + } while (x != e); + } + } +}; + +struct Arrangement : DoublyConnectedEdgeList { + vector segs; + + unordered_map> adj; // (Vertex, Vertex) -> Edge + + struct Node { // Sweep-Line Structure (RBST) + int index, size = 1; + Node *left = 0, *right = 0; + } *root = 0; + vector ns; + Node *update(Node *x) { + if (x) { + x->size = 1; + if (x->left) x->size += x->left->size; + if (x->right) x->size += x->right->size; + } + return x; + } + Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (rand() % (x->size + y->size) < x->size) { + x->right = merge(x->right, y); + return update(x); + } else { + y->left = merge(x, y->left); + return update(y); + } + } + template // 3-way split: cond(x) < 0, cond(x) == 0, cond(x) > 0 + tuple split(Node *x, C cond) { + if (!x) return make_tuple(x,x,x); + if (cond(x) == 0) { + auto a = split(x->left, cond); + auto b = split(x->right, cond); + x->left = x->right = 0; update(x); + get<1>(a) = merge(merge(get<1>(a), x), get<1>(b)); + get<2>(a) = get<2>(b); + return a; + } + if (cond(x) < 0) { + auto a = split(x->right, cond); + x->right = 0; update(x); + get<0>(a) = merge(x, get<0>(a)); + return a; + } + if (cond(x) > 0) { + auto a = split(x->left, cond); + x->left = 0; update(x); + get<2>(a) = merge(get<2>(a), x); + return a; + } + } + Node *leftmost(Node *x) { while (x && x->left) x = x->left; return x; } + Node *rightmost(Node *x) { while (x && x->right) x = x->right; return x; } + template + void process(Node *x, F func) { + if (!x) return; + process(x->left, func); + func(x); + process(x->right, func); + } + + Arrangement(vector segs_) : segs(segs_) { + ns.resize(segs.size()); + set events; + map> L, R; + + for (int i = 0; i < segs.size(); ++i) { + if (segs[i].q < segs[i].p) swap(segs[i].p, segs[i].q); + events.insert(segs[i].p); + events.insert(segs[i].q); + L[segs[i].p].insert(i); + R[segs[i].q].insert(i); + ns[i].index = i; + } + vector last(segs.size(), -1); + + while (!events.empty()) { + const Point p = *events.begin(); + events.erase(events.begin()); + int u = newVertex(p); + + auto cond = [&](Node *x) { + const Segment &s = segs[x->index]; + if (sign(s.q.x - s.p.x) == 0) { + if (sign(p.y - s.p.y) < 0) return -1; + if (sign(s.q.y - p.y) < 0) return +1; + return 0; + } + return -sign(cross(s.p - p, s.q - p)); + }; + auto z = split(root, cond); + vector inserter; + process(get<1>(z), [&](Node *x) { + int v = last[x->index]; + if (!adj[u].count(v)) { + int e = newEdge(u), f = newEdge(v); + adj[u][v] = e; + adj[v][u] = f; + edge[e].twin = f; + edge[f].twin = e; + } + if (!R[p].count(x->index)) + inserter.push_back(x); + }); + for (int i: L[p]) + if (!R[p].count(i)) + inserter.push_back(&ns[i]); + sort(all(inserter), [&](Node *x, Node *y) { + const Segment &s = segs[x->index], &t = segs[y->index]; + return sign(cross(s.q - s.p, t.q - t.p)) >= 0; + }); + auto addEvent = [&](Node *x, Node *y) { + if (!x || !y) return; + vector ps = intersect(segs[x->index], segs[y->index]); + for (Point q: ps) + if (p < q) events.insert(q); + }; + if (inserter.empty()) { + addEvent(rightmost(get<0>(z)), leftmost(get<2>(z))); + } else { + addEvent(rightmost(get<0>(z)), inserter[0]); + addEvent(leftmost(get<2>(z)), inserter.back()); + } + root = 0; + for (int i = 0; i < inserter.size(); ++i) { + last[inserter[i]->index] = u; + inserter[i]->left = inserter[i]->right = 0; + root = merge(root, update(inserter[i])); + } + root = merge(merge(get<0>(z), root), get<2>(z)); + } + for (auto &pp: adj) { + int u = pp.fst; + vector es; + for (auto z: pp.snd) es.push_back(z.snd); + sort(all(es), [&](int e, int f) { + auto quad = [](Point p) { + for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y)) + if (p.x > 0 && p.y >= 0) return i; + return 0; + }; + const Point p = point[edge[edge[e].twin].vertex] - point[edge[e].vertex]; + const Point q = point[edge[edge[f].twin].vertex] - point[edge[f].vertex]; + if (quad(p) != quad(q)) return quad(p) < quad(q); + return sign(cross(p, q)) > 0; + }); + vertex[u].edge = es.back(); + for (int e: es) { + edge[vertex[u].edge].next = e; + edge[edge[vertex[u].edge].next].prev = vertex[u].edge; + vertex[u].edge = edge[vertex[u].edge].next; + } + } + } +}; +void AOJ1226() { + for (int n; ~scanf("%d", &n) && n; ) { + vector> a(4, vector(n)); + for (int k = 0; k < 4; ++k) + for (int i = 0; i < n; ++i) + scanf("%lf", &a[k][i]); + + vector ss = { + {{0,0},{0,1}}, + {{0,1},{1,1}}, + {{1,1},{1,0}}, + {{1,0},{0,0}} + }; + for (int i = 0; i < n; ++i) { + ss.push_back({{a[0][i],0},{a[1][i],1}}); + ss.push_back({{0,a[2][i]},{1,a[3][i]}}); + } + Arrangement arr(ss); + arr.completeFaces(); + + double result = 0; + for (int f = 0; f < arr.face.size(); ++f) { + double area = 0; + int e = arr.face[f].edge; + do { + area += cross(arr.point[arr.edge[e].vertex], + arr.point[arr.edge[arr.edge[e].twin].vertex]), + e = arr.edge[arr.edge[e].twin].prev; + } while (e != arr.face[f].edge); + result = max(result, area); + } + printf("%.6f\n", result/2); + } +} +void AOJ2448() { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + vector ss; + for (int i = 0; i+1 < n; ++i) + ss.push_back({ps[i], ps[i+1]}); + Arrangement arr(ss); + arr.completeFaces(); + + double result = 0; + for (int f = 0; f < arr.face.size(); ++f) { + double area = 0; + int e = arr.face[f].edge; + do { + area += cross(arr.point[arr.edge[e].vertex], + arr.point[arr.edge[arr.edge[e].twin].vertex]), + e = arr.edge[arr.edge[e].twin].prev; + } while (e != arr.face[f].edge); + if (area > 0) result += area; + } + printf("%.12f\n", result/2); +} + +int main() { + // AOJ2448(); + AOJ1226(); +} + From 2ac92f9f738aaa7cf935ffc05792c19c7ee90eb0 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 10:48:38 +0900 Subject: [PATCH 078/141] Bentley-Ottman's Segment Arrangement in O(k log n). --- geometry/segment_arrangement.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/geometry/segment_arrangement.cc b/geometry/segment_arrangement.cc index c3233e6..7d3f8ab 100644 --- a/geometry/segment_arrangement.cc +++ b/geometry/segment_arrangement.cc @@ -10,6 +10,10 @@ // Complexity: // O(k log n), where k is the size of input. // +// Verified: +// AOJ 1226 +// AOJ 2448 +// // References: // CGAA // From dd674a0b8ea0ac7bb6f8108f138fc94007ad10f1 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 12:01:07 +0900 Subject: [PATCH 079/141] Bentley-Ottman Segment Arrangement --- geometry/segment_arrangement.cc | 111 ++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/geometry/segment_arrangement.cc b/geometry/segment_arrangement.cc index 7d3f8ab..86d2212 100644 --- a/geometry/segment_arrangement.cc +++ b/geometry/segment_arrangement.cc @@ -88,34 +88,47 @@ vector intersect(Segment s, Segment t) { return ps; } + +// +// each vertex has one incident edge +// each edge has the origin vertex, twin edge, and the left face. +// two edges (prev, next) representing a list of edges surrounding a face. +// struct DoublyConnectedEdgeList { - struct Vertex { int edge; }; // incident - struct Edge { int vertex, twin, prev, next, face; }; // origin, twin, incident list, left face - struct Face { int edge; }; // any incident face + vector incident_edge; // vertex + vector origin, twin, prev, next, incident_face; // edge + vector component; // face + int edges() const { return origin.size(); } + int vertices() const { return incident_edge.size(); } + int faces() const { return component.size(); } + vector point; - vector vertex; - vector edge; - vector face; int newVertex(Point p, int e = -1) { point.push_back(p); - vertex.push_back({e}); - return vertex.size()-1; + incident_edge.push_back(e); + return vertices()-1; + } + int newEdge(int o = -1) { + origin.push_back(o); + twin.push_back(-1); + prev.push_back(-1); + next.push_back(-1); + incident_face.push_back(-1); + return edges()-1; } - int newEdge(int vertex = -1) { - edge.push_back({vertex, -1, -1, -1, -1}); - return edge.size()-1; + int newFace(int e = -1) { + component.push_back(e); + return component.size()-1; } void completeFaces() { - face.clear(); - for (int e = 0; e < edge.size(); ++e) edge[e].face = -1; - for (int e = 0; e < edge.size(); ++e) { - if (edge[e].face >= 0) continue; - int f = face.size(); - face.push_back({e}); - int x = e; + component.clear(); + fill(all(incident_face), -1); + for (int e = 0; e < edges(); ++e) { + if (incident_face[e] >= 0) continue; + int f = newFace(e), x = e; do { - edge[x].face = f; - x = edge[edge[x].twin].prev; + incident_face[x] = f; + x = next[x]; } while (x != e); } } @@ -183,7 +196,6 @@ struct Arrangement : DoublyConnectedEdgeList { func(x); process(x->right, func); } - Arrangement(vector segs_) : segs(segs_) { ns.resize(segs.size()); set events; @@ -213,7 +225,7 @@ struct Arrangement : DoublyConnectedEdgeList { } return -sign(cross(s.p - p, s.q - p)); }; - auto z = split(root, cond); + auto z = split(root, cond); vector inserter; process(get<1>(z), [&](Node *x) { int v = last[x->index]; @@ -221,8 +233,8 @@ struct Arrangement : DoublyConnectedEdgeList { int e = newEdge(u), f = newEdge(v); adj[u][v] = e; adj[v][u] = f; - edge[e].twin = f; - edge[f].twin = e; + twin[e] = f; + twin[f] = e; } if (!R[p].count(x->index)) inserter.push_back(x); @@ -230,6 +242,7 @@ struct Arrangement : DoublyConnectedEdgeList { for (int i: L[p]) if (!R[p].count(i)) inserter.push_back(&ns[i]); + sort(all(inserter), [&](Node *x, Node *y) { const Segment &s = segs[x->index], &t = segs[y->index]; return sign(cross(s.q - s.p, t.q - t.p)) >= 0; @@ -254,28 +267,33 @@ struct Arrangement : DoublyConnectedEdgeList { } root = merge(merge(get<0>(z), root), get<2>(z)); } + vector next_inc(next.size()), prev_inc(prev.size()); for (auto &pp: adj) { int u = pp.fst; vector es; for (auto z: pp.snd) es.push_back(z.snd); - sort(all(es), [&](int e, int f) { + sort(all(es), [&](int e, int f) { // polar sort auto quad = [](Point p) { for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y)) if (p.x > 0 && p.y >= 0) return i; return 0; }; - const Point p = point[edge[edge[e].twin].vertex] - point[edge[e].vertex]; - const Point q = point[edge[edge[f].twin].vertex] - point[edge[f].vertex]; + const Point p = point[origin[twin[e]]] - point[origin[e]]; + const Point q = point[origin[twin[f]]] - point[origin[f]]; if (quad(p) != quad(q)) return quad(p) < quad(q); return sign(cross(p, q)) > 0; }); - vertex[u].edge = es.back(); - for (int e: es) { - edge[vertex[u].edge].next = e; - edge[edge[vertex[u].edge].next].prev = vertex[u].edge; - vertex[u].edge = edge[vertex[u].edge].next; + incident_edge[u] = es[0]; + for (int i = 0; i < es.size(); ++i) { + int j = (i + 1) % es.size(); + next_inc[es[i]] = es[j]; + prev_inc[es[j]] = es[i]; } } + for (int e = 0; e < edges(); ++e) { + next[e] = prev_inc[twin[e]]; + prev[e] = twin[next_inc[e]]; + } } }; void AOJ1226() { @@ -299,14 +317,14 @@ void AOJ1226() { arr.completeFaces(); double result = 0; - for (int f = 0; f < arr.face.size(); ++f) { + for (int f = 0; f < arr.faces(); ++f) { double area = 0; - int e = arr.face[f].edge; + int e = arr.component[f]; do { - area += cross(arr.point[arr.edge[e].vertex], - arr.point[arr.edge[arr.edge[e].twin].vertex]), - e = arr.edge[arr.edge[e].twin].prev; - } while (e != arr.face[f].edge); + area += cross(arr.point[arr.origin[e]], + arr.point[arr.origin[arr.twin[e]]]), + e = arr.next[e]; + } while (e != arr.component[f]); result = max(result, area); } printf("%.6f\n", result/2); @@ -324,21 +342,20 @@ void AOJ2448() { arr.completeFaces(); double result = 0; - for (int f = 0; f < arr.face.size(); ++f) { + for (int f = 0; f < arr.faces(); ++f) { double area = 0; - int e = arr.face[f].edge; + int e = arr.component[f]; do { - area += cross(arr.point[arr.edge[e].vertex], - arr.point[arr.edge[arr.edge[e].twin].vertex]), - e = arr.edge[arr.edge[e].twin].prev; - } while (e != arr.face[f].edge); + area += cross(arr.point[arr.origin[e]], + arr.point[arr.origin[arr.twin[e]]]), + e = arr.next[e]; + } while (e != arr.component[f]); if (area > 0) result += area; } printf("%.12f\n", result/2); } int main() { - // AOJ2448(); - AOJ1226(); + AOJ2448(); + //AOJ1226(); } - From 995cf29c0f28e583e31e928d4f4d2b9f301b53a5 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 02:19:35 -0600 Subject: [PATCH 080/141] Coordinate Domination --- geometry/coordinate_domination.cc | 89 +++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 geometry/coordinate_domination.cc diff --git a/geometry/coordinate_domination.cc b/geometry/coordinate_domination.cc new file mode 100644 index 0000000..ec23e35 --- /dev/null +++ b/geometry/coordinate_domination.cc @@ -0,0 +1,89 @@ +// +// 3D Coordinate-Wise Domination +// +// Description: +// +// Point (x,y,z) dominates (x',y',z') if +// x < x', y < y', and z < z' +// holds. Kung-Luccio-Preparata proposed an algorithm to compute +// the all set of dominating points in O(n log n) time. +// +// It maintains a data structure to check the domination efficiently +// in (y,z)-plane, and proceed the points in the decreasing order of x. +// By the processing order, the new point is only dominated by the +// previously processed points. Also, by the processing order, the +// new point is dominated if its (y,z) coordinate is dominated. +// By using a data structure, it is efficiently checked. +// +// Complexity: +// +// O(n log n). By using this method recursively, +// we can solve d-dimensional domination in O(n log^{d-2} n). +// +// Reference: +// +// Hsiang-Tsung Kung, Fabrizio Luccio, Franco P. Preparata (1975): +// "On finding the maxima of a set of vectors." Journal of the ACM, +// vol.22, no.4, pp.469-476. +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Real = int; +struct Point { + Real x, y, z; + bool operator < (Point p) const { + if (x != p.x) return x < p.x; + if (y != p.y) return y < p.y; + return z < p.z; + } +}; +int domination(vector xs) { + multiset frontier; + auto bad = [&](multiset::iterator it) { + auto jt = next(it); + if (jt == frontier.end()) return false; + return it->y < jt->y && it->z < jt->z; + }; + int n = xs.size(); + sort(all(xs)); + int count = 0; + for (int i = n-1; i >= 0; --i) { + auto proc = [&] { + if (i < n-1 && xs[i].x == xs[i+1].x) return true; + Point p(xs[i]); p.x = 0; + auto it = frontier.insert(p); + if (bad(it)) { + frontier.erase(it); + return false; + } else { + while (it != frontier.begin() && bad(prev(it))) + frontier.erase(prev(it)); + return true; + } + }; + if (proc()) ++count; + } + return count; +} + + +int main() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) { + scanf("%d %d %d", &ps[i].x, &ps[i].y, &ps[i].z); + ps[i].x = -ps[i].x; + ps[i].y = -ps[i].y; + ps[i].z = -ps[i].z; + } + printf("%d\n", domination(ps)); + } +} From 5ec70c5deb385040459a9d7002587518f1242d43 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 02:21:44 -0600 Subject: [PATCH 081/141] Coordinate Domination --- geometry/coordinate_domination.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/geometry/coordinate_domination.cc b/geometry/coordinate_domination.cc index ec23e35..6bbb728 100644 --- a/geometry/coordinate_domination.cc +++ b/geometry/coordinate_domination.cc @@ -8,12 +8,11 @@ // holds. Kung-Luccio-Preparata proposed an algorithm to compute // the all set of dominating points in O(n log n) time. // -// It maintains a data structure to check the domination efficiently -// in (y,z)-plane, and proceed the points in the decreasing order of x. -// By the processing order, the new point is only dominated by the -// previously processed points. Also, by the processing order, the -// new point is dominated if its (y,z) coordinate is dominated. -// By using a data structure, it is efficiently checked. +// It maintains a data structure to check the domination in (y,z) plane, +// and proceed the points in the decreasing order of x. +// By the processing order, the new point is never dominated by the latter +// points and is dominated by the previous points if its (y,z) coordinate +// is dominated by them. // // Complexity: // From d09957fd1384463f339e3c682f2e3346d0fc136b Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 14:49:58 -0600 Subject: [PATCH 082/141] Suffix Automaton --- string/suffix_automaton.cc | 149 +++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 string/suffix_automaton.cc diff --git a/string/suffix_automaton.cc b/string/suffix_automaton.cc new file mode 100644 index 0000000..a4315f8 --- /dev/null +++ b/string/suffix_automaton.cc @@ -0,0 +1,149 @@ +// +// Suffix Automaton +// +// Description: +// +// It is an automaton that accepts all suffixes +// of a given string. +// +// Verified: +// +// SPOJ_SUBST1 +// SPOJ_SUBLEX +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct SuffixAutomaton { + vector length = {0}, parent = {-1}; + vector> next = {map()}; + int size() const { return next.size(); } + + int extend(int p, int c) { + int head = next.size(); + next.push_back(map()); + length.push_back(length[p]+1); + parent.push_back(0); + while (p >= 0 && !next[p].count(c)) { + next[p][c] = head; + p = parent[p]; + } + if (p >= 0) { + int q = next[p][c]; + if (length[p]+1 == length[q]) { + parent[head] = q; + } else { + int clone = next.size(); // clone of q + length.push_back(length[p]+1); + parent.push_back(parent[q]); + next.push_back(next[q]); + parent[q] = parent[head] = clone; + while (p >= 0 && next[p][c] == q) { + next[p][c] = clone; + p = parent[p]; + } + } + } + return head; + } + vector topological_order; + SuffixAutomaton(const char s[]) { // can be constructed online + int p = 0; + for(int i = 0; s[i]; ++i) + p = extend(p, s[i]); + vector mark(size()); // topological sort + for (int i = 0; i < size(); ++i) + for (auto z: next[i]) ++mark[z.snd]; + topological_order.push_back(0); + for (int i = 0; i < size(); ++i) + for (auto z: next[i]) + if (--mark[z.snd] == 0) topological_order.push_back(z.snd); + } + template // topological order + void process(F func) { + for (int i = 0; i < topological_order.size(); ++i) func(i); + } + template + void processRev(F func) { // reverse topological order + for (int i = topological_order.size()-1; i >= 0; --i) func(i); + } +}; +int countDistinctSubstrings(const char s[]) { + SuffixAutomaton M(s); + vector dp(M.size()); + int ans = 0; + dp[0] = 1; + M.process([&](int i) { + ans += dp[i]; + for (auto z: M.next[i]) + dp[z.snd] += dp[i]; + }); + return ans; +} + +string kthSubstring(const char s[], int k) { + SuffixAutomaton M(s); + vector num_terminal(M.size()); // preprocess that can be reused + M.processRev([&](int i) { + num_terminal[i] = 1; + for (auto z: M.next[i]) + num_terminal[i] += num_terminal[z.snd]; + }); + string ret; // answer to query + for (int p = 0; k-- > 0; ) { + for (auto z: M.next[p]) { + if (num_terminal[z.snd] > k) { + ret.push_back(z.fst); + p = z.snd; break; + } else k -= num_terminal[z.snd]; + } + } + return ret; +} + +void SPOJ_SUBST1() { + int ncase; + scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + char s[100000]; + scanf("%s", s); + printf("%d\n", countDistinctSubstrings(s)-1); + } +} +void SPOJ_SUBLEX() { + char s[100000]; + scanf("%s", s); + SuffixAutomaton M(s); + + vector num_terminal(M.size()); + M.processRev([&](int i) { + num_terminal[i] = 1; + for (auto z: M.next[i]) + num_terminal[i] += num_terminal[z.snd]; + }); + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int k; scanf("%d", &k); + string ret; + for (int p = 0; k-- > 0; ) { + for (auto z: M.next[p]) { + if (num_terminal[z.snd] > k) { + ret.push_back(z.fst); + p = z.snd; break; + } else k -= num_terminal[z.snd]; + } + } + printf("%s\n", ret.c_str()); + } +} + +int main() { + //SPOJ_SUBST1(); + SPOJ_SUBLEX(); +} From 938aa43edfcdbab6591ea599858ad23ac4b5ce36 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 15:10:26 -0600 Subject: [PATCH 083/141] Suffix Automaton --- string/suffix_automaton.cc | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/string/suffix_automaton.cc b/string/suffix_automaton.cc index a4315f8..8e6e64a 100644 --- a/string/suffix_automaton.cc +++ b/string/suffix_automaton.cc @@ -1,16 +1,33 @@ // -// Suffix Automaton +// Suffix Automaton (aka. Suffix Directed Acyclic Word Graph) // // Description: // // It is an automaton that accepts all suffixes -// of a given string. +// of a given string. It can be constructed in O(n) time +// by using Blumer et al.'s online construction. +// +// Note that a factor automaton is obtained from +// the suffix automaton by setting the all states as terminal. +// +// Complexity: +// O(n) // // Verified: // // SPOJ_SUBST1 // SPOJ_SUBLEX // +// References: +// A. Blumer, J. Blumer, D. Haussler, A. Ehrenfeucht, +// M. T. Chen, and J. Seiferas (1985): +// The smallest automation recognizing the subwords of a text. +// Theoretical Computer Science, vol. 40, pp. 31-55. +// +// M. Crochemore, and W. Rytter (1994): +// Text Algorithms. +// Oxford University Press. +// #include using namespace std; @@ -21,32 +38,33 @@ using namespace std; #define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } struct SuffixAutomaton { - vector length = {0}, parent = {-1}; + vector length = {0}; // maximum length corresponding to the node + vector link = {-1}; // suffix link of the node vector> next = {map()}; int size() const { return next.size(); } int extend(int p, int c) { int head = next.size(); - next.push_back(map()); length.push_back(length[p]+1); - parent.push_back(0); + link.push_back(0); + next.push_back(map()); while (p >= 0 && !next[p].count(c)) { next[p][c] = head; - p = parent[p]; + p = link[p]; } if (p >= 0) { int q = next[p][c]; if (length[p]+1 == length[q]) { - parent[head] = q; + link[head] = q; } else { int clone = next.size(); // clone of q length.push_back(length[p]+1); - parent.push_back(parent[q]); + link.push_back(link[q]); next.push_back(next[q]); - parent[q] = parent[head] = clone; + link[q] = link[head] = clone; while (p >= 0 && next[p][c] == q) { next[p][c] = clone; - p = parent[p]; + p = link[p]; } } } From ee9c42395f8673b4eed5b3918ce8c1fa463e85b8 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 15:10:45 -0600 Subject: [PATCH 084/141] Delete factor_automaton.cc --- string/factor_automaton.cc | 134 ------------------------------------- 1 file changed, 134 deletions(-) delete mode 100644 string/factor_automaton.cc diff --git a/string/factor_automaton.cc b/string/factor_automaton.cc deleted file mode 100644 index 6b38e12..0000000 --- a/string/factor_automaton.cc +++ /dev/null @@ -1,134 +0,0 @@ -// -// Factor Automaton (aka. Directed Acyclig Word Graph) -// -// Description: -// For a given string s, the factor automaton is an -// automaton that accepts all substrings s[i,j). -// The automaton has O(n) state. -// -// Algorithm: -// Blumer et al's online construction. -// See Section 6.3 of Crochemore-Rytter. -// -// Complexity: -// O(n) time and space. -// -// Verified: -// SPOJ 22531 -// -// References: -// A. Blumer, J. Blumer, D. Haussler, A. Ehrenfeucht, -// M. T. Chen, and J. Seiferas (1985): -// The smallest automation recognizing the subwords of a text. -// Theoretical Computer Science, vol. 40, pp. 31-55. -// -// M. Crochemore, and W. Rytter (1994): -// Text Algorithms. -// Oxford University Press. -// -#include -#include -#include -#include -#include -#include - -using namespace std; - -#define fst first -#define snd second -#define all(c) ((c).begin()), ((c).end()) - -struct factor_automaton { - vector> link; - vector> bold; - vector suf; - int root; - int add_node() { - link.push_back(vector(0x100)); - bold.push_back(vector(0x100)); - suf.push_back(0); - return link.size()-1; - } - factor_automaton(const char s[]) { - add_node(); // = nil - int sink = root = add_node(); - suf[root] = 0; - for (int i = 0; s[i]; ++i) { - char a = s[i]; - int newsink = add_node(); - link[sink][a] = newsink; - bold[sink][a] = true; - int w = suf[sink]; - while (w != 0 && link[w][a] == 0) { - link[w][a] = newsink; - bold[w][a] = false; - w = suf[w]; - } - int v = link[w][a]; - if (w == 0) suf[newsink] = root; - else if (bold[w][a]) suf[newsink] = v; - else { - int newnode = add_node(); - link[newnode] = link[v]; - link[w][a] = newnode; - bold[w][a] = true; - suf[newsink] = newnode; - suf[newnode] = suf[v]; - suf[v] = newnode; - w = suf[w]; - while (w != 0 && link[w][a] == v && bold[w][a] == false) { - link[w][a] = newnode; - w = suf[w]; - } - } - sink = newsink; - } - } - - void disp() { - cout << "--- display ---" << endl; - for (int i = 1; i < link.size(); ++i) { - cout << " state " << i << endl; - for (int c = 0; c < 0x100; ++c) { - if (link[i][c] > 0) { - if (bold[i][c]) cout << " ==" << (char)c << "==> " << link[i][c] << endl; - else cout << " --" << (char)c << "--> " << link[i][c] << endl; - } - } - } - - } -}; - - -int main() { - for (char text[100000]; ~scanf("%s", text); ) { - factor_automaton FA(text); - - vector> prev(FA.link.size()); - queue que; - que.push(FA.root); - while (prev[0].fst == 0) { - int s = que.front(); - que.pop(); - for (int c = 'A'; c <= 'Z'; ++c) { - //for (int c = 'A'; c <= 'B'; ++c) { // for test - if (prev[FA.link[s][c]].fst == 0) { - prev[FA.link[s][c]] = {s, c}; - que.push(FA.link[s][c]); - //cout << s << " --" << (char)c << "--> " << FA.link[s][c] << endl; - } - } - } - int s = 0; - vector result; - do { - result.push_back(prev[s].snd); - s = prev[s].fst; - } while (s > 1); - for (int i = result.size()-1; i >= 0; --i) - printf("%c", result[i]); - printf("\n"); - } -} From b6dcd8f85e16e856bf777586bce4fcbe5250a5ac Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 16:50:06 -0600 Subject: [PATCH 085/141] Automatic Differentiation by Dual Numbers --- math/dual_number.cc | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 math/dual_number.cc diff --git a/math/dual_number.cc b/math/dual_number.cc new file mode 100644 index 0000000..33fe5df --- /dev/null +++ b/math/dual_number.cc @@ -0,0 +1,58 @@ +// +// Automatic Differentiation by Dual Numbers +// +// Description: +// +// Dual number is an extended real number of the form a + epsilon b, +// where epsilon is the first order infinitesimal (i.e, epsilon^2 = 0). +// By overloading each function for dual numbers, as in the code, +// we can obtain the derivative of f at a by evaluating f(a + epsilon). +// +// Complexity: +// +// Linear in composition depth. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Real = double; +struct DualNumber { + Real a, b; // a + epsilon b + DualNumber(Real a = 0, Real b = 0) : a(a), b(b) { } + DualNumber &operator+=(DualNumber x) { b+=x.b; a+=x.a; return *this; } + DualNumber &operator*=(DualNumber x) { b=b*x.a+a*x.b; a*=x.a; return *this; } + DualNumber operator+() const { return *this; } + DualNumber operator-() const { return {-a, -b}; } + DualNumber inv() const { return {1.0/a, -b/(a*a)}; } + DualNumber &operator-=(DualNumber x) { return *this += -x; } + DualNumber &operator/=(DualNumber x) { return *this *= x.inv(); } +}; +DualNumber operator+(DualNumber x, DualNumber y) { return x += y; } +DualNumber operator-(DualNumber x, DualNumber y) { return x -= y; } +DualNumber operator*(DualNumber x, DualNumber y) { return x *= y; } +DualNumber operator/(DualNumber x, DualNumber y) { return x /= y; } + +// define functions with its derivative +DualNumber pow(DualNumber x, Real e) { return {pow(x.a,e),x.b*pow(x.a,e-1)}; } +DualNumber sqrt(DualNumber x) { return pow(x,0.5); } +DualNumber exp(DualNumber x) { return {exp(x.a),x.b*exp(x.a)}; } +DualNumber cos(DualNumber x) { return {cos(x.a),-x.b*sin(x.a)}; } +DualNumber sin(DualNumber x) { return {sin(x.a),x.b*cos(x.a)}; } +DualNumber tan(DualNumber x) { return sin(x)/cos(x); } +DualNumber log(DualNumber x) { return {log(x.a),x.b/x.a}; } + +int main() { + DualNumber x = 3, y = 4; + auto f = [&](DualNumber x) { + return sin(x*x) + cos(exp(x)) + tan(x); + }; + x.b = 1; // set infinitesimal part + cout << f(x).b << endl; +} + From b7238a5f95fc7e1200e8323f990e6af7fdab0f0d Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 16:56:22 -0600 Subject: [PATCH 086/141] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 6200a46..3e06bb1 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,9 @@ You can use the codes for *any purpose without any warranty*. author: Takanori MAEHARA (web: http://www.prefield.com, e-mail: maehara@prefield.com, twitter: @tmaehara) + +# Recruiting + +I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute on artificial intelligence related areas. In particular, I am working on discrete algorithms (including topics in this github repository). + +We are hiring highly-skilled programmers and researchers who are interested in working with us. If you are intersted in, please feel free to contact me by email or something else. From ea229deec65b5b0070efb3c80f407250d28432c6 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 17:03:31 -0600 Subject: [PATCH 087/141] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e06bb1..c225377 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,7 @@ author: Takanori MAEHARA (web: http://www.prefield.com, e-mail: maehara@prefield I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute on artificial intelligence related areas. In particular, I am working on discrete algorithms (including topics in this github repository). -We are hiring highly-skilled programmers and researchers who are interested in working with us. If you are intersted in, please feel free to contact me by email or something else. +We are hiring programmers and researchers. The criterion is, basically, +- Programmer: having some strong achievements in some competitions (e.g., ICPC, Google Code Jam, CodeForces, etc...). +- Researcher: having some strong publications in some CS area (e.g., SODA/ICALP/IPCO, NIPS/ICML, AAAI/IJCAI, etc...). +If you are interested in, please feel free to contact me. From 5c5402934bca270232df4623b73d36f5cb2e22ca Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 17:06:00 -0600 Subject: [PATCH 088/141] Update README.md --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index c225377..8700f08 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,4 @@ author: Takanori MAEHARA (web: http://www.prefield.com, e-mail: maehara@prefield # Recruiting -I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute on artificial intelligence related areas. In particular, I am working on discrete algorithms (including topics in this github repository). - -We are hiring programmers and researchers. The criterion is, basically, -- Programmer: having some strong achievements in some competitions (e.g., ICPC, Google Code Jam, CodeForces, etc...). -- Researcher: having some strong publications in some CS area (e.g., SODA/ICALP/IPCO, NIPS/ICML, AAAI/IJCAI, etc...). -If you are interested in, please feel free to contact me. +I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute on artificial intelligence related areas. In particular, I am working on discrete algorithms (including topics in this github repository). We are hiring *strong programmers/researchers* who has some achievements in some competitions. If you are interested in, please feel free to contact me. From 220c173a2b76a6098a3d664e20d79093fc835cae Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 6 Jan 2018 17:06:48 -0600 Subject: [PATCH 089/141] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8700f08..4ca0646 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,4 @@ author: Takanori MAEHARA (web: http://www.prefield.com, e-mail: maehara@prefield # Recruiting -I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute on artificial intelligence related areas. In particular, I am working on discrete algorithms (including topics in this github repository). We are hiring *strong programmers/researchers* who has some achievements in some competitions. If you are interested in, please feel free to contact me. +I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute. I am working on discrete algorithms (including topics in this github repository). We are hiring *strong programmers/researchers* who has some achievements in some competitions. If you are interested in, please feel free to contact me. From fb739fd03ce8675104a71328cb26bc87ddb2b94f Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 7 Jan 2018 10:57:41 +0900 Subject: [PATCH 090/141] Segment Arrangement (Bentley-Ottman's Plane-Sweep) --- geometry/segment_arrangement.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geometry/segment_arrangement.cc b/geometry/segment_arrangement.cc index 86d2212..ebdd923 100644 --- a/geometry/segment_arrangement.cc +++ b/geometry/segment_arrangement.cc @@ -8,7 +8,7 @@ // time, where k is the size of output. // // Complexity: -// O(k log n), where k is the size of input. +// O(k log n), where k is the size of output. // // Verified: // AOJ 1226 From e95eb8590abbb72bb1c98fca72a372ca599e75c4 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 7 Jan 2018 03:56:40 -0600 Subject: [PATCH 091/141] Prufer Code in O(n) --- graph/prufer_code.cc | 112 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 graph/prufer_code.cc diff --git a/graph/prufer_code.cc b/graph/prufer_code.cc new file mode 100644 index 0000000..8e4b877 --- /dev/null +++ b/graph/prufer_code.cc @@ -0,0 +1,112 @@ +// +// Prufer Code in Linear Time +// +// Description: +// Prufer code gives one-to-one correspondence +// between labeled trees and integers of length n-2. +// This immediately shows the Cayley theorem: +// the number of labeled trees is n^{n-2}. +// The algorithm computes the Prufer code in linear +// time. +// +// Complexity: +// O(n) +// +// Reference: +// Xiaodong Wang, Lei Wang, and Yingjie Wui (2009): +// "An Optimal Algorithm for Prufer Codes", +// Journal of Software Engineering and Applications, +// vol.2, 111--115. +// + +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Tree { + int n; + vector> adj; + Tree(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); + } +}; + +vector labeledTreeToCode(Tree T) { + vector deg(T.n), parent(T.n, -1), code; + function dfs = [&](int u) { + deg[u] = T.adj[u].size(); + for (int v: T.adj[u]) { + if (v != parent[u]) { + parent[v] = u; + dfs(v); + } + } + }; dfs(T.n-1); + + int index = -1; + while (deg[++index] != 1); + for (int u = index, i = 0; i < T.n-2; ++i) { + int v = parent[u]; + code.push_back(v); + if (--deg[v] == 1 && v < index) { + u = v; + } else { + while (deg[++index] != 1); + u = index; + } + } + return code; +} + +Tree codeToLabeledTree(vector code) { + int n = code.size() + 2; + Tree T(n); + vector deg(n, 1); + for (int i = 0; i < n-2; ++i) + ++deg[code[i]]; + + int index = -1; + while (deg[++index] != 1); + for (int u = index, i = 0; i < n-2; ++i) { + int v = code[i]; + T.addEdge(u, v); + --deg[u]; --deg[v]; + if (deg[v] == 1 && v < index) { + u = v; + } else { + while (deg[++index] != 1); + u = index; + } + } + for (int u = 0; u < n-1; ++u) + if (deg[u] == 1) T.addEdge(u, n-1); + return T; +} + +int main() { + Tree T(6); + T.addEdge(0, 3); + T.addEdge(1, 3); + T.addEdge(2, 3); + T.addEdge(3, 4); + T.addEdge(4, 5); + auto code = labeledTreeToCode(T); + for (int u: code) { + cout << u << " "; + } + cout << endl; + + Tree G = codeToLabeledTree(code); + for (int u = 0; u < G.adj.size(); ++u) { + for (int v: G.adj[u]) { + if (u < v) cout << u << " " << v << endl; + } + } +} From bcdecdd6191c054a3583fcec845efa2ee4bc3f8f Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 7 Jan 2018 04:01:37 -0600 Subject: [PATCH 092/141] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ca0646..b51f54d 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,4 @@ author: Takanori MAEHARA (web: http://www.prefield.com, e-mail: maehara@prefield # Recruiting -I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute. I am working on discrete algorithms (including topics in this github repository). We are hiring *strong programmers/researchers* who has some achievements in some competitions. If you are interested in, please feel free to contact me. +I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute. I am working on discrete algorithms (including topics in this github repository). We are hiring *strong programmers* who has some achievements in some competitions. If you are interested in, please feel free to contact me. From c64100bd11a658744cecf681c1fbdc8cb334dc05 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 8 Jan 2018 15:41:45 -0600 Subject: [PATCH 093/141] Bounded Knapsack Problem in O(nW) time --- dynamic_programming/bounded_knapsack.cc | 134 ++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 dynamic_programming/bounded_knapsack.cc diff --git a/dynamic_programming/bounded_knapsack.cc b/dynamic_programming/bounded_knapsack.cc new file mode 100644 index 0000000..9dc1ce9 --- /dev/null +++ b/dynamic_programming/bounded_knapsack.cc @@ -0,0 +1,134 @@ +// +// Bounded Knapsack Problem +// +// Description: +// +// There are n kinds of items of profit pi, weight bi, and +// amount mi (i in {0...n}). For a given W, we want to select items +// to maximize the total profit subject to the total weight +// is at most W and the number of each item is at most mi. +// +// This problem can be solved by the following DP. +// E[j][w] = max {E[j-1][w], E[j-1][w-bj]+pj, E[j-1][w-2bj]+2pj. ...} +// A naive implementation requires O(nmW) time. However, we can reduce +// this to O(nW) as follows. +// +// We compute E[j][s], E[j][s+bj]. E[s+2bj] ... for each s in [0,bj). +// For simplicity, we consider s = 0. Then, we have +// E[j][w+bj] = max {E[j-1][w+bj], E[j-1][w]+pj, E[j-1][w-bj]+2pj. ...} +// By comparing this with the original formula, +// - E[j][w+bj] contains E[j-1][w+bj] term +// - E[j][w+bj] does not contain E[j-1][w-mjbj] term +// - The all terms have been added pj +// Thus, by using a data structure that supports these operations, +// we can perform the DP efficiently. The data structure is implemented +// by a sliding maximum queue with one additional integer parameter. +// +// Complexity: +// +// O(n W) +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +// Minimum Queue or Sliding Minimum Data Dtructure +// +// 3 1 4 1 +// 1 4 1 +template +struct MinQueue { + queue que; + deque peek; + T alpha = 0; + void push(T a) { + a -= alpha; + que.push(a); + while (!peek.empty() && peek.back() > a) peek.pop_back(); + peek.push_back(a); + } + void pop() { + if (que.front() == peek.front()) peek.pop_front(); + que.pop(); + } + T front() const { return que.front()+alpha; } + T min() const { return peek.front()+alpha; } + void add(T a) { alpha += a; } // does not change the ordering +}; + +int boundedKnapsackDP(vector ps, + vector ws, + vector ms, + int W) { + int n = ps.size(); + vector> dp(n+1, vector(W+1)); + for (int i = 0; i < n; ++i) { + for (int s = 0; s < ws[i]; ++s) { + int alpha = 0; + queue que; + deque peek; + for (int w = s; w <= W; w += ws[i]) { + alpha += ps[i]; + int a = dp[i][w]-alpha; + que.push(a); + while (!peek.empty() && peek.back() < a) peek.pop_back(); + peek.push_back(a); + while (que.size() > ms[i]+1) { + if (que.front() == peek.front()) peek.pop_front(); + que.pop(); + } + dp[i+1][w] = peek.front()+alpha; + } + } + } + int ans = 0; + for (int w = 0; w <= W; ++w) + ans = max(ans, dp[n][w]); + return ans; +} + +int boundedKnapsackDPNaive(vector ps, + vector ws, + vector ms, + int W) { + int n = ps.size(); + vector> dp(n+1, vector(W+1)); + for (int i = 0; i < n; ++i) { + for (int w = 0; w <= W; ++w) { + dp[i+1][w] = dp[i][w]; + for (int j = 1; j <= ms[i]; ++j) { + if (w - j*ws[i] < 0) break; + dp[i+1][w] = max(dp[i+1][w], dp[i][w-j*ws[i]]+j*ps[i]); + } + } + } + int ans = 0; + for (int w = 0; w <= W; ++w) + ans = max(ans, dp[n][w]); + return ans; +} + +int main() { + int seed; + seed = 20; + //cin >> seed; + seed = time(0); + srand(seed); + int n = 100; + int W = 10000; + vector ps(n), ws(n), ms(n); + for (int i = 0; i < n; ++i) { + ps[i] = rand() % n + 1; + ws[i] = rand() % n + 1; + ms[i] = rand() % n + 1; + //cout << ps[i] << " " << ws[i] << " " << ms[i] << endl; + } + + cout << boundedKnapsackDP(ps, ws, ms, W) << endl; + cout << boundedKnapsackDPNaive(ps, ws, ms, W) << endl; +} From 2bcb86f2751548841d77c0db1db3e32adf99b5dd Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 8 Jan 2018 15:43:48 -0600 Subject: [PATCH 094/141] Bounded Knapsack Problem in O(nW) time --- dynamic_programming/bounded_knapsack.cc | 26 +------------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/dynamic_programming/bounded_knapsack.cc b/dynamic_programming/bounded_knapsack.cc index 9dc1ce9..84b1402 100644 --- a/dynamic_programming/bounded_knapsack.cc +++ b/dynamic_programming/bounded_knapsack.cc @@ -22,7 +22,7 @@ // - The all terms have been added pj // Thus, by using a data structure that supports these operations, // we can perform the DP efficiently. The data structure is implemented -// by a sliding maximum queue with one additional integer parameter. +// by a maximum queue with one accumulation parameter. // // Complexity: // @@ -37,30 +37,6 @@ using namespace std; #define all(c) ((c).begin()), ((c).end()) #define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } -// Minimum Queue or Sliding Minimum Data Dtructure -// -// 3 1 4 1 -// 1 4 1 -template -struct MinQueue { - queue que; - deque peek; - T alpha = 0; - void push(T a) { - a -= alpha; - que.push(a); - while (!peek.empty() && peek.back() > a) peek.pop_back(); - peek.push_back(a); - } - void pop() { - if (que.front() == peek.front()) peek.pop_front(); - que.pop(); - } - T front() const { return que.front()+alpha; } - T min() const { return peek.front()+alpha; } - void add(T a) { alpha += a; } // does not change the ordering -}; - int boundedKnapsackDP(vector ps, vector ws, vector ms, From 47c1996ce0cd69f6c2c441674968d9e4839c73e9 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 9 Jan 2018 20:28:04 +0900 Subject: [PATCH 095/141] Kd-Tree --- geometry/kd_tree.cc | 180 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 geometry/kd_tree.cc diff --git a/geometry/kd_tree.cc b/geometry/kd_tree.cc new file mode 100644 index 0000000..48f2df2 --- /dev/null +++ b/geometry/kd_tree.cc @@ -0,0 +1,180 @@ +// +// Kd-Tree +// +// Description: +// +// Kd-Tree is a spatial partitioning tree defined as follows[1]. +// Each node has a point, called a pivot, and its left +// and right childs store the points that are lefter and righter +// on the pivot. Here, "left" and "right" are defined by the +// coordinate that switches cyclically over the depth. +// +// The Kd-Tree has the depth O(log n), and if the input is random, +// the searching has complexity O(log n) in expectation. +// However, in an adversarial input, the worst case complexity +// becomes O(n^{1-1/d}), which tends to a naive bound as d to infty[2]. +// +// Note: Computing NNs for n points requires O(n^{2-1/d}) time. +// Basically, it is practical and has advantage over the naive search +// if n = 10^5. +// +// Complexity: +// +// Construction: O(n log n) +// Nearest Neighbor: O(n^{1-1/d}) in worst case, +// O(log n) in random case. +// +// References: +// +// [1] Jon Louis Bentley (1975): +// "Multidimensional binary search trees used for associative searching." +// Communications of the ACM, vol. 18, no. 9, pp. 509--517. +// +// [2] Der-Tsai Lee and C. K. Wong (1977): +// "Worst-case analysis for region and partial region searches in +// multidimensional binary search trees and balanced quad trees." +// Acta Informatica, vol.9, no.1, pp. 23--29. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +using Real = long double; +const Real PI = acos(-1.0); +const Real EPS = 1e-8; +int sign(Real x) { return (x > EPS) - (x < -EPS); } +struct Point { + Real x, y; + Point &operator+=(Point p) { x += p.x; y += p.y; return *this; } + Point &operator*=(Real a) { x *= a; y *= a; return *this; } + Point operator+() const { return {+x, +y}; } + Point operator-() const { return {-x, -y}; } + + Point &operator-=(Point p) { return *this += -p; } + Point &operator/=(Real a) { return *this *= 1/a; } +}; +Point operator+(Point p, Point q) { return p += q; } +Point operator-(Point p, Point q) { return p -= q; } +Point operator*(Real a, Point p) { return p *= a; } +Point operator*(Point p, Real a) { return p *= a; } +Point operator/(Point p, Real a) { return p /= a; } + +int compare(Point p, Point q) { + int s = sign(p.x - q.x); + return s ? s : sign(p.y - q.y); +} +bool operator==(Point p, Point q) { return compare(p,q)==0; } +bool operator!=(Point p, Point q) { return compare(p,q)!=0; } +bool operator<=(Point p, Point q) { return compare(p,q)<=0; } +bool operator>=(Point p, Point q) { return compare(p,q)>=0; } +bool operator<(Point p, Point q) { return compare(p,q)<0; } +bool operator>(Point p, Point q) { return compare(p,q)>0; } + +Real dot(Point p, Point q) { return p.x*q.x+p.y*q.y; } +Real cross(Point p, Point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +Real norm2(Point p) { return dot(p,p); } +Point orth(Point p) { return {-p.y, p.x}; } +Real norm(Point p) { return sqrt(dot(p,p)); } +Real arg(Point p) { return atan2(p.y, p.x); } +Real arg(Point p, Point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, Point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const Point &p) { os<<"("< ps; + KdTree(vector ps) : ps(ps) { + int idx[ps.size()]; + iota(idx, idx+ps.size(), 0); + root = build<0>(idx, idx+ps.size()); + } + template + Node *build(int *l, int *r) { + if (l - r >= 0) return 0; + auto comp = [&](int i, int j) { + if (d == 0) return ps[i].x < ps[j].x; + if (d == 1) return ps[i].y < ps[j].y; + }; + int *m = l + (r-l)/2; + nth_element(l, m, r, comp); + return new Node({*m, build(l,m), build(m+1,r)}); + } + template + void nearestNeighborSearchRec(Node *x, Point p, pair &ub) { + if (!x) return; + Point q = p - ps[x->id]; + Real r = norm(q), w; + if (r < ub.fst) ub = {r, x->id}; + if (d == 0) w = q.x; + else w = q.y; + Node *fst = x->left, *snd = x->right; + if (w > 0) swap(fst, snd); + nearestNeighborSearchRec(fst, p, ub); + if (ub.fst > abs(w)) nearestNeighborSearchRec(snd, p, ub); + } + int nearestNeighbor(Point p) { + pair ub(1.0/0.0, -1); + nearestNeighborSearchRec<0>(root, p, ub); + return ub.snd; + } + + + // for verification + int nearestNeighborNaive(Point p) { + int id = 0; + for (int i = 1; i < ps.size(); ++i) + if (norm(ps[i] - p) < norm(ps[id] - p)) id = i; + return id; + } + void display(Node *x, int tab=0) { + if (!x) return; + display(x->left, tab+2); + cout << string(tab, ' ') << x->id << ": " << ps[x->id] << endl; + display(x->right,tab+2); + } +}; +int main() { + int n = 10000; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = rand() % n; + ps[i].y = rand() % n; + } + KdTree T(ps); + //T.display(T.root); + + double t1 = 0, t2 = 0; + for (int k = 0; k < n; ++k) { + Point p = {rand() % n, rand() % n}; + tick(); + Point q = ps[T.nearestNeighbor(p)]; + t1 += tick(); + Point r = ps[T.nearestNeighborNaive(p)]; + t2 += tick(); + TEST(sign(norm(q-p) - norm(r-p)) == 0); + //cout << p << " " << norm(q - p) << " " << norm(r - p) << endl; + } + cout << t1 << " [s] by Kd search" << endl << + t2 << " [s] by naive search" << endl; +} From 2f7430f0139f7d03d9f5f9a2bdc8a697bc69ca19 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 9 Jan 2018 06:02:53 -0600 Subject: [PATCH 096/141] Bounded Knapsack Problem in O(nW) time --- dynamic_programming/bounded_knapsack.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic_programming/bounded_knapsack.cc b/dynamic_programming/bounded_knapsack.cc index 84b1402..0bff66f 100644 --- a/dynamic_programming/bounded_knapsack.cc +++ b/dynamic_programming/bounded_knapsack.cc @@ -4,7 +4,7 @@ // Description: // // There are n kinds of items of profit pi, weight bi, and -// amount mi (i in {0...n}). For a given W, we want to select items +// amount mi (i in {0...n-1}). For a given W, we want to select items // to maximize the total profit subject to the total weight // is at most W and the number of each item is at most mi. // From 2aae310a170e5283ddf026fc81734770f48fe06f Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 11 Jan 2018 15:50:27 +0900 Subject: [PATCH 097/141] Random Ball Cover --- geometry/random_ball_cover.cc | 225 ++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 geometry/random_ball_cover.cc diff --git a/geometry/random_ball_cover.cc b/geometry/random_ball_cover.cc new file mode 100644 index 0000000..f2266b2 --- /dev/null +++ b/geometry/random_ball_cover.cc @@ -0,0 +1,225 @@ +// +// Random Ball Cover +// +// Description: +// +// Random ball cover is a data structure for metric nearest neighbor +// search. It is useful if the only distance function is available, +// and/or dimension is moderately large (10 to 1000). +// +// It first select O(sqrt{n})-size random sample from the points as +// representatives. Then, it assigns other points to the nearest +// representatives. The search procedure uses the triangle inequality +// to prune unnecessary searching. +// +// +// Complexity: +// +// Construction: O(n log n). +// Search: O(sqrt(n)) in a random distribution. +// +// +// Reference: +// +// Lawrence Cayton (2012): +// "Accelerating nearest neighbor search on manycore systems." +// Parallel & Distributed Processing Symposium (IPDPS), +// in IPDPS, pp.402-413. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + + +using Real = long double; +const Real PI = acos(-1.0); +const Real EPS = 1e-8; +int sign(Real x) { return (x > EPS) - (x < -EPS); } +struct Point { + Real x, y; + Point &operator+=(Point p) { x += p.x; y += p.y; return *this; } + Point &operator*=(Real a) { x *= a; y *= a; return *this; } + Point operator+() const { return {+x, +y}; } + Point operator-() const { return {-x, -y}; } + + Point &operator-=(Point p) { return *this += -p; } + Point &operator/=(Real a) { return *this *= 1/a; } +}; +Point operator+(Point p, Point q) { return p += q; } +Point operator-(Point p, Point q) { return p -= q; } +Point operator*(Real a, Point p) { return p *= a; } +Point operator*(Point p, Real a) { return p *= a; } +Point operator/(Point p, Real a) { return p /= a; } + +int compare(Point p, Point q) { + int s = sign(p.x - q.x); + return s ? s : sign(p.y - q.y); +} +bool operator==(Point p, Point q) { return compare(p,q)==0; } +bool operator!=(Point p, Point q) { return compare(p,q)!=0; } +bool operator<=(Point p, Point q) { return compare(p,q)<=0; } +bool operator>=(Point p, Point q) { return compare(p,q)>=0; } +bool operator<(Point p, Point q) { return compare(p,q)<0; } +bool operator>(Point p, Point q) { return compare(p,q)>0; } + +Real dot(Point p, Point q) { return p.x*q.x+p.y*q.y; } +Real cross(Point p, Point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +Real norm2(Point p) { return dot(p,p); } +Point orth(Point p) { return {-p.y, p.x}; } +Real norm(Point p) { return sqrt(dot(p,p)); } +Real arg(Point p) { return atan2(p.y, p.x); } +Real arg(Point p, Point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, Point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const Point &p) { os<<"("< ps; + vector>> list; + RandomBallCover(vector ps) : ps(ps) { + int n = ps.size(), sqrtn = sqrt(n + 0.5); + vector idx(n); + iota(all(idx), 0); + random_shuffle(all(idx)); + for (int i = 0; i < sqrtn; ++i) + list.push_back({make_pair(0.0, idx[i])}); + for (int i = sqrtn; i < n; ++i) { + Real nearest = 1.0/0.0; + int id; + for (int j = 0; j < sqrtn; ++j) { + Real d = dist(ps[list[j][0].snd], ps[idx[i]]); + if (nearest > d) { + nearest = d; + id = j; + } + } + list[id].push_back({nearest, idx[i]}); + } + for (int i = 0; i < list.size(); ++i) + sort(all(list[i])); + } + int nearestNeighbor(Point p) { + vector dis(list.size()), rem(list.size()); + vector cand(list.size()); + Real best = 1.0/0.0; + int id; + for (int i = 0; i < list.size(); ++i) { + dis[i] = dist(p, ps[list[i][0].snd]); + if (dis[i] < best) { + best = dis[i]; + id = list[i][0].snd; + } + cand[i] = i; + } + sort(all(cand), [&](int i, int j) { return dis[i] < dis[j]; }); + for (int i: cand) { + for (int k = list[i].size()-1; k >= 0; --k) { + if (best <= dis[i] - list[i][k].fst) break; + int j = list[i][k].snd; + Real d = dist(p, ps[j]); + if (d < best) { + best = d; + id = j; + } + } + } + return id; + } + int nearestNeighborNaive(Point p) { + int id = 0; + for (int i = 0; i < ps.size(); ++i) + if (dist(p, ps[id]) > dist(p, ps[i])) id = i; + return id; + } +}; + + +// for comparison +// Kd-Tree for k = 2 +struct KdTree { + struct Node { + int id; + Node *left, *right; + } *root = 0; + vector ps; + KdTree(vector ps) : ps(ps) { + int idx[ps.size()]; + iota(idx, idx+ps.size(), 0); + root = build<0>(idx, idx+ps.size()); + } + template + Node *build(int *l, int *r) { + if (l - r >= 0) return 0; + auto comp = [&](int i, int j) { + if (d == 0) return ps[i].x < ps[j].x; + if (d == 1) return ps[i].y < ps[j].y; + }; + int *m = l + (r-l)/2; + nth_element(l, m, r, comp); + return new Node({*m, build(l,m), build(m+1,r)}); + } + template + void nearestNeighborSearchRec(Node *x, Point p, pair &ub) { + if (!x) return; + Point q = p - ps[x->id]; + Real r = norm(q), w; + if (r < ub.fst) ub = {r, x->id}; + if (d == 0) w = q.x; + else w = q.y; + Node *fst = x->left, *snd = x->right; + if (w > 0) swap(fst, snd); + nearestNeighborSearchRec(fst, p, ub); + if (ub.fst > abs(w)) nearestNeighborSearchRec(snd, p, ub); + } + int nearestNeighbor(Point p) { + pair ub(1.0/0.0, -1); + nearestNeighborSearchRec<0>(root, p, ub); + return ub.snd; + } +}; + +int main() { + int n = 10000; + vector ps; + for (int i = 0; i < n; ++i) { + Real x = rand() % n; + Real y = rand() % n; + ps.push_back({x, y}); + } + RandomBallCover X(ps); + KdTree T(ps); + double t1 = 0, t2 = 0; + for (int i = 0; i < n; ++i) { + Real x = rand() % n; + Real y = rand() % n; + Point p = {x, y}; + tick(); + int j = X.nearestNeighbor(p); + t1 += tick(); + int k = T.nearestNeighbor(p); + t2 += tick(); + assert(sign(norm(p - ps[j]) - norm(p - ps[k])) == 0); + } + cout << t1 << " " << t2 << endl; +} From ee567e83da9dc714ccac3566e71554e457a2e6cd Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 13 Jan 2018 20:46:58 +0900 Subject: [PATCH 098/141] Hopcroft's DA Minimization --- string/dfa_minimization.cc | 295 +++++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 string/dfa_minimization.cc diff --git a/string/dfa_minimization.cc b/string/dfa_minimization.cc new file mode 100644 index 0000000..6628589 --- /dev/null +++ b/string/dfa_minimization.cc @@ -0,0 +1,295 @@ +// +// Deterministic Finite Automata Minimization +// +// Description: +// +// Hopcroft minimization algorithm. See Wikipedia. +// +// Complexity: +// +// O(|A| n log n). +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Automaton { + vector> trans; + vector is_accept; + int init = 0; + int next(int state, int a) { return trans[state][a]; } + bool accept(int state) { return is_accept[state]; } + int size() { return trans.size(); } +}; +template +Automaton minimizeAutomaton(AM A) { + // remove unreachables + vector seen(A.size()); + seen[A.init] = 1; + vector partition = {A.init}, pos, label; + for (int i = 0; i < partition.size(); ++i) { + pos.push_back(i); + label.push_back(0); + int state = partition[i]; + for (int a = 0; a <= 9; ++a) { + int state_ = A.next(state, a); + if (!seen[state_]) { + seen[state_] = 1; + partition.push_back(state_); + } + } + } + // make inverse mapping + vector inverse[partition.size()][10]; + for (int i = 0; i < partition.size(); ++i) { + int state = partition[i]; + for (int a = 0; a <= 9; ++a) { + inverse[A.next(state, a)][a].push_back(state); + } + } + // Hopcroft minimization + vector begin = {0}, mid = {0}, end = {partition.size()}; + auto mark = [&](int state) { + int x = label[state]; + if (pos[state] < mid[x]) return; + int state_ = partition[mid[x]++]; + swap(pos[state], pos[state_]); + swap(partition[pos[state]], partition[pos[state_]]); + }; + auto refine = [&](int x) { + if (mid[x] == begin[x]) return -1; + if (mid[x] == end[x]) { mid[x] = begin[x]; return -1; } + int y = begin.size(); + if (mid[x] - begin[x] < end[x] - mid[x]) { + begin.push_back(begin[x]); + end.push_back(mid[x]); + mid.push_back(begin[x]); + begin[x] = mid[x]; + } else { + begin.push_back(mid[x]); + end.push_back(end[x]); + mid.push_back(mid[x]); + end[x] = mid[x]; + mid[x] = begin[x]; + } + for (int i = begin.back(); i < end.back(); ++i) + label[partition[i]] = y; + return y; + }; + for (int state: partition) + if (A.accept(state)) mark(state); + + if (refine(0) >= 0) { // do Hopcroft minimization + fill(all(seen), 0); + seen[0] = seen[1] = 1; + vector process = {0, 1}; + vector is_suspect(partition.size()); + while (!process.empty()) { + int x = process.back(); process.pop_back(); + seen[x] = 0; + for (int a = 0; a <= 9; ++a) { + vector suspect; + for (int i = begin[x]; i < end[x]; ++i) { + int u = partition[i]; + for (int state: inverse[u][a]) { + int y = label[state]; + mark(state); + if (!is_suspect[y]) { + is_suspect[y] = 1; + suspect.push_back(y); + } + } + } + for (int y: suspect) { + is_suspect[y] = 0; + int z = refine(y); + if (z < 0) continue; + if (seen[y]) { + process.push_back(z); + seen[z] = 1; + } else { + if (end[y] - begin[y] < end[z] - begin[z]) { + process.push_back(y); + seen[y] = 1; + } else { + process.push_back(z); + seen[z] = 1; + } + } + } + } + } + } + Automaton M; // completion + M.trans.assign(begin.size(), vector(10)); + M.is_accept.resize(begin.size()); + for (int x = 0; x < begin.size(); ++x) { + int state = partition[begin[x]]; + M.is_accept[x] = A.accept(state); + for (int a = 0; a <= 9; ++a) { + int y = label[A.next(state, a)]; + M.trans[x][a] = label[A.next(state, a)]; + } + } + M.init = label[A.init]; + return M; +} + + +// state = x : x == n % mod +struct ModuloAutomaton { + int mod; + ModuloAutomaton(int mod) : mod(mod) { } + int init = 0; + int size() { return mod; } + int next(int state, int a) { return (10 * state + a) % mod; } + bool accept(int state) { return state == 0; } +}; +// state = 0 : empty +// 1 : fail +// 2 ... 10 : singleton and last number is state-1 +// 11 ... 19 : increased and last number is state-10 +// 20 ... 28 : decreased and last number is state-20 +struct ZigZagAutomaton { + int init = 0; + int size() { return 29; } + int next(int state, int a) { + if (state == 0) return a == 0 ? 0 : a + 1; + if (state == 1) return 1; + if (state <= 10) { + int last = state - 1; + if (a > last) return a + 10; + else if (a < last) return a + 20; + } else if (state <= 19) { + int last = state - 10; + if (a < last) return a + 20; + } else if (state <= 28) { + int last = state - 20; + if (a > last) return a + 10; + } + return 1; + } + bool accept(int state) { return state != 1; } +}; +template +Automaton intersectionAutomaton(Automaton1 A, Automaton2 B) { + Automaton M; + vector> table(A.size(), vector(B.size(), -1)); + vector x = {A.init}, y = {B.init}; + table[x[0]][y[0]] = 0; + for (int i = 0; i < x.size(); ++i) { + M.trans.push_back(vector(10, -1)); + M.is_accept.push_back(A.accept(x[i]) && B.accept(y[i])); + for (int a = 0; a <= 9; ++a) { + int u = A.next(x[i], a), v = B.next(y[i], a); + if (table[u][v] == -1) { + table[u][v] = x.size(); + x.push_back(u); + y.push_back(v); + } + M.trans[i][a] = table[u][v]; + } + } + return M; +} + +template +int digitDP(string num, Automaton A, int eq = 1) { + int n = num.size(); + vector>> dp(n+1); + + dp[0] = vector>(2, vector(A.size())); + dp[0][1][A.init] = 1; + auto addTo = [&](int &x, int y) { + if ((x += y) >= 10000) x -= 10000; + }; + for (int i = 0; i < n; ++i) { + dp[i+1] = vector>(2, vector(A.size())); + for (int tight = 0; tight <= 1; ++tight) { + for (int state = 0; state < A.size(); ++state) { + if (dp[i][tight][state] == 0) continue; + int lim = (tight ? num[i] - '0' : 9); + for (int d = 0; d <= lim; ++d) { + int tight_ = tight && d == lim; + int state_ = A.next(state, d); + addTo(dp[i+1][tight_][state_], dp[i][tight][state]); + } + } + } + dp[i].clear(); + } + int ans = 0; + for (int tight = 0; tight <= eq; ++tight) + for (int state = 0; state < A.size(); ++state) + if (A.accept(state)) addTo(ans, dp[n][tight][state]); + return ans; +} + +template +int debug(string num, Automaton A) { + function rec + = [&](int i, int tight, int state, string s) { + if (i == num.size()) { + if (A.accept(state)) cout << s << endl; + return; + } + int lim = (tight ? num[i] - '0' : 9); + for (int d = 0; d <= lim; ++d) { + int tight_ = tight && d == lim; + int state_ = A.next(state, d); + s.push_back('0' + d); + rec(i+1, tight_, state_, s); + s.pop_back(); + } + }; + rec(0, 1, A.init, ""); +} + +void AOJ_ZIGZAG() { + char A[1000], B[1000]; + int M; + scanf("%s %s %d", A, B, &M); + ZigZagAutomaton zigzag; + ModuloAutomaton modulo(M); + auto IM = minimizeAutomaton(intersectionAutomaton(zigzag, modulo)); + int a = digitDP(A, IM, 0); + int b = digitDP(B, IM, 1); + cout << (b + (10000 - a)) % 10000 << endl; + { + auto IM = intersectionAutomaton(zigzag, modulo); + int a = digitDP(A, IM, 0); + int b = digitDP(B, IM, 1); + cout << (b + (10000 - a)) % 10000 << endl; + } +} +int main() { + AOJ_ZIGZAG(); + /* + Automaton A; + A.trans.assign(7, vector(10, 6)); + A.trans[0][0] = 1; + A.trans[0][1] = 2; + A.trans[1][0] = 0; + A.trans[1][1] = 3; + A.trans[2][0] = 4; + A.trans[2][1] = 5; + A.trans[3][0] = 4; + A.trans[3][1] = 5; + A.trans[4][0] = 4; + A.trans[4][1] = 5; + A.trans[5][0] = 5; + A.trans[5][1] = 5; + A.is_accept.assign(7, 0); + A.is_accept[2] = 1; + A.is_accept[3] = 1; + A.is_accept[4] = 1; + auto B = minimizeAutomaton(A); + cout << B.size() << endl; + */ + //minimizeAutomaton(ZigZagAutomaton()); +} From 7af336c54a9df8ee8d57d6c553cf8b3ca93141f6 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 13 Jan 2018 20:47:39 +0900 Subject: [PATCH 099/141] Hopcroft's DFA Minimization --- string/dfa_minimization.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/string/dfa_minimization.cc b/string/dfa_minimization.cc index 6628589..731338a 100644 --- a/string/dfa_minimization.cc +++ b/string/dfa_minimization.cc @@ -260,12 +260,6 @@ void AOJ_ZIGZAG() { int a = digitDP(A, IM, 0); int b = digitDP(B, IM, 1); cout << (b + (10000 - a)) % 10000 << endl; - { - auto IM = intersectionAutomaton(zigzag, modulo); - int a = digitDP(A, IM, 0); - int b = digitDP(B, IM, 1); - cout << (b + (10000 - a)) % 10000 << endl; - } } int main() { AOJ_ZIGZAG(); From f91a0c45ce42fc36bb13318b11f7c78d947f82f7 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 13 Jan 2018 21:37:35 +0900 Subject: [PATCH 100/141] Digit DP (most generalized form) --- dynamic_programming/digit_dp.cc | 225 ++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 dynamic_programming/digit_dp.cc diff --git a/dynamic_programming/digit_dp.cc b/dynamic_programming/digit_dp.cc new file mode 100644 index 0000000..4b72a97 --- /dev/null +++ b/dynamic_programming/digit_dp.cc @@ -0,0 +1,225 @@ +// +// Digit DP +// +// Description: +// +// Digit DP is a framework to solve problems of counting +// the numbers less than equal to a given number and +// whose digits satisfy some constraint. +// +// More generally, it can compute the sum-product +// sum { prod(x) : 0 <= x <= z } +// where +// prod(x) = (((e * x[0]) * x[1])...) * x[n-1]. +// +// The sum operator + is required to be commutative, and +// right-distributive with respect to * as +// (u + v) * d = (u * d + v * d) +// +// The constraint of digits should be represented by a +// finite automaton that reads digits from left to right. +// The DP has the table +// dp[digit][tight][status] +// with the following DP +// +// dp[0][1][M.init] = e +// for (int i = 0; i < n; ++i) { +// for (int tight = 0; tight <= 1; ++tight) { +// for (int state = 0; state < M.size(); ++state) { +// int lim = tight ? 'z'-0 : 9; +// for (int d = 0; d <= lim; ++d) { +// oplusTo(dp[i+1][tight&&d==lim][next(state,d)], +// otimes(dp[i][tight][state], d)); +// } +// } +// } +// } +// for (int tight = 0; tight <= 1; ++tight) +// for (int state = 0; state < M.size(); ++state) +// if (M.accept(state)) oplusTo(ans, dp[n][tight][state]; +// return ans; +// +// Verified: +// SPOJ_CPCRC1C +// AOJ_ZIGZAG + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + + +// struct Value { +// Value &operator+(Value y) +// Value &operator*(int d) +// }; +// struct Automaton { +// int init +// int size() +// int next(int state, int d) +// bool accept(int state) +// }; +template +Value digitDP(string z, Value e, Automaton M, bool eq = 1) { + struct Maybe { + Value value; + bool undefined = true; + }; + auto oplusTo = [&](Maybe &x, Maybe y) { + if (x.undefined) x = y; + else if (!y.undefined) x.value += y.value; + }; + auto otimes = [&](Maybe x, int d) { + x.value *= d; + return x; + }; + int n = z.size(); + vector> curr(2, vector(M.size())); + curr[1][M.init] = {e, false}; + for (int i = 0; i < n; ++i) { + vector> next(2, vector(M.size())); + for (int tight = 0; tight <= 1; ++tight) { + for (int state = 0; state < M.size(); ++state) { + if (curr[tight][state].undefined) continue; + int lim = (tight ? z[i] - '0' : 9); + for (int d = 0; d <= lim; ++d) { + int tight_ = tight && d == lim; + int state_ = M.next(state, d); + oplusTo(next[tight_][state_], otimes(curr[tight][state], d)); + } + } + } + curr = next; + } + Maybe ans; + for (int tight = 0; tight <= eq; ++tight) + for (int state = 0; state < M.size(); ++state) + if (M.accept(state)) oplusTo(ans, curr[tight][state]); + return ans.value; +} + +template +string toString(T x) { + stringstream ss; + ss << x; + return ss.str(); +} + +using Int = long long; +Int sumOfDigits(string z, bool eq = true) { + struct Value { + Int count, sum; + Value &operator+=(Value y) { count+=y.count; sum+=y.sum; return *this; } + Value &operator*=(int d) { sum+=count*d; return *this; } + }; + struct Automaton { + int init = 0; + int size() { return 1; } + int next(int s, int d) { return 0; } + int accept(int s) { return true; } + }; + return digitDP(z, (Value){1,0}, Automaton(), eq).sum; +} +void SPOJ_CPCRC1C() { + for (long long a, b; cin >> a >> b; ) { + if (a < 0 && b < 0) break; + cout << sumOfDigits(toString(b), true) + - sumOfDigits(toString(a), false) << endl; + } +} + +struct Automaton { + vector> trans; + vector is_accept; + int init = 0; + int next(int state, int a) { return trans[state][a]; } + bool accept(int state) { return is_accept[state]; } + int size() { return trans.size(); } +}; +template +Automaton intersectionAutomaton(Automaton1 A, Automaton2 B) { + Automaton M; + vector> table(A.size(), vector(B.size(), -1)); + vector x = {A.init}, y = {B.init}; + table[x[0]][y[0]] = 0; + for (int i = 0; i < x.size(); ++i) { + M.trans.push_back(vector(10, -1)); + M.is_accept.push_back(A.accept(x[i]) && B.accept(y[i])); + for (int a = 0; a <= 9; ++a) { + int u = A.next(x[i], a), v = B.next(y[i], a); + if (table[u][v] == -1) { + table[u][v] = x.size(); + x.push_back(u); + y.push_back(v); + } + M.trans[i][a] = table[u][v]; + } + } + return M; +} + +void AOJ_ZIGZAG() { + char A[1000], B[1000]; + int M; + scanf("%s %s %d", A, B, &M); + + struct Value { + int value = 0; + Value &operator+=(Value x) { + if ((value += x.value) >= 10000) value -= 10000; + return *this; + } + Value &operator*=(int d) { + return *this; + } + } e = (Value){1}; + + // state = 0 : empty + // 1 : fail + // 2 ... 10 : singleton and last number is state-1 + // 11 ... 19 : increased and last number is state-10 + // 20 ... 28 : decreased and last number is state-20 + struct ZigZagAutomaton { + int init = 0; + int size() { return 29; } + int next(int state, int a) { + if (state == 0) return a == 0 ? 0 : a + 1; + if (state == 1) return 1; + if (state <= 10) { + int last = state - 1; + if (a > last) return a + 10; + else if (a < last) return a + 20; + } else if (state <= 19) { + int last = state - 10; + if (a < last) return a + 20; + } else if (state <= 28) { + int last = state - 20; + if (a > last) return a + 10; + } + return 1; + } + bool accept(int state) { return state != 1; } + } zigzag; + + // state = x : x == n % mod + struct ModuloAutomaton { + int mod; + ModuloAutomaton(int mod) : mod(mod) { } + int init = 0; + int size() { return mod; } + int next(int state, int a) { return (10 * state + a) % mod; } + bool accept(int state) { return state == 0; } + } modulo(M); + + auto IM = intersectionAutomaton(zigzag, modulo); + int a = digitDP(A, e, IM, 0).value; + int b = digitDP(B, e, IM, 1).value; + cout << (b + (10000 - a)) % 10000 << endl; +} + +int main() { + //SPOJ_CPCRC1C(); + AOJ_ZIGZAG(); +} From 7e2755e65a7aa324154bcb62b68769ad1afa5d69 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 13 Jan 2018 23:40:13 +0900 Subject: [PATCH 101/141] Longest ZigZag Subsequence in O(n) --- .../longest_zigzag_sequence.cc | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 dynamic_programming/longest_zigzag_sequence.cc diff --git a/dynamic_programming/longest_zigzag_sequence.cc b/dynamic_programming/longest_zigzag_sequence.cc new file mode 100644 index 0000000..0f31ad9 --- /dev/null +++ b/dynamic_programming/longest_zigzag_sequence.cc @@ -0,0 +1,64 @@ +// +// Longest ZigZag Subsequence +// +// Description: +// +// A sequence xs is zigzag if x[i] < x[i+1], x[i+1] > x[i+2], for all i +// (initial direction can be arbitrary). The maximum length zigzag +// subsequence is computed in O(n) time by a greedy method. +// +// First, we contract contiguous same numbers. Then, the number of +// peaks corresponds to the longest zig-zag subsequence. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +int longestZigZagSubsequence(vector xs) { + int n = xs.size(), len = 1, prev = -1; + for (int i = 0, j; i < n; i = j) { + for (j = i+1; j < n && xs[i] == xs[j]; ++j); + if (j < n) { + int sign = (xs[i] < xs[j]); + if (prev != sign) ++len; + prev = sign; + } + } + return len; +} + +// DP for verification +template +int longestZigZagSubsequenceN(vector A) { + int n = A.size(); + vector> Z(n, vector(2)); + Z[0][0] = 1; + Z[0][1] = 1; + int best = 1; + for(int i = 1; i < n; i++){ + for(int j = i-1; j>= 0; j--){ + if(A[j] < A[i]) Z[i][0] = max(Z[j][1]+1, Z[i][0]); + if(A[j] > A[i]) Z[i][1] = max(Z[j][0]+1, Z[i][1]); + } + best = max(best, max(Z[i][0],Z[i][1])); + } + return best; +} + +int main() { + for (int seed = 0; seed < 10000; ++seed) { + srand(seed); + int n = 100; + vector a(n); + for (int i = 0; i < n; ++i) { + a[i] = rand() % n; + } + assert(longestZigZagSubsequence(a) == longestZigZagSubsequenceN(a)); + } +} From d454c58e1c4271d486798e84401b2c7b49da469d Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 13 Jan 2018 23:40:52 +0900 Subject: [PATCH 102/141] Longest ZigZag Subsequence in O(n) --- .../{longest_zigzag_sequence.cc => longest_zigzag_subsequence.cc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dynamic_programming/{longest_zigzag_sequence.cc => longest_zigzag_subsequence.cc} (100%) diff --git a/dynamic_programming/longest_zigzag_sequence.cc b/dynamic_programming/longest_zigzag_subsequence.cc similarity index 100% rename from dynamic_programming/longest_zigzag_sequence.cc rename to dynamic_programming/longest_zigzag_subsequence.cc From b305b6d53fb7cf654938e85870b14b9859fef98e Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 18:43:18 +0900 Subject: [PATCH 103/141] General DigitDP --- dynamic_programming/digit_dp.cc | 52 ++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/dynamic_programming/digit_dp.cc b/dynamic_programming/digit_dp.cc index 4b72a97..33bf5cd 100644 --- a/dynamic_programming/digit_dp.cc +++ b/dynamic_programming/digit_dp.cc @@ -107,6 +107,17 @@ string toString(T x) { return ss.str(); } +// +// Sum of digits. +// Since sum is not distributive, (u + v) + d != (u + d + v + d), +// we need to augment the number to contain the number of numbers. +// Let + and * be defined by +// (u,a) + (v,b) = (u+v,a+b), +// (u,a) * d = (u+a*d,a). +// Then, they are right-distributive as +// ((u,a) + (v,b)) * c = (u+v,a+b) * c = (u+v+ac+bc,a+b), +// (u,a) * c + (v,b) * c = (u+ac,a) + (v+bc,b) = (u+v+ac+bc,a+b). +// using Int = long long; Int sumOfDigits(string z, bool eq = true) { struct Value { @@ -160,6 +171,13 @@ Automaton intersectionAutomaton(Automaton1 A, Automaton2 B) { return M; } +// +// Count the zigzag numbers that is a multiple of M. +// Here, a number is zigzag if its digits are alternatively +// increasing and decreasing, like 14283415... +// Since there are multiple conditions, we use automaton +// composition to simplify the approach. +// void AOJ_ZIGZAG() { char A[1000], B[1000]; int M; @@ -219,7 +237,39 @@ void AOJ_ZIGZAG() { cout << (b + (10000 - a)) % 10000 << endl; } +// +// Count the numbers that does not contain 4 and 7 in each digit. +// +void ABC007D() { + string a, b; + cin >> a >> b; + + struct ForbiddenNumber { + int init = 0; + int size() { return 2; } + int next(int state, int a) { + if (state == 1) return 1; + if (a == 4 || a == 9) return 1; + return 0; + } + bool accept(int state) { return state == 1; } + }; + struct Counter { + long long value = 0; + Counter &operator+=(Counter x) { + value += x.value; + return *this; + } + Counter &operator*=(int d) { + return *this; + } + }; + cout << digitDP(b, (Counter){1}, ForbiddenNumber(), true).value + - digitDP(a, (Counter){1}, ForbiddenNumber(), false).value << endl; +} + int main() { + ABC007D(); //SPOJ_CPCRC1C(); - AOJ_ZIGZAG(); + //AOJ_ZIGZAG(); } From 0c1fc116a41295c6b919312dde43f0c85886cc56 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 18:46:34 +0900 Subject: [PATCH 104/141] General Digit DP --- dynamic_programming/digit_dp.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dynamic_programming/digit_dp.cc b/dynamic_programming/digit_dp.cc index 33bf5cd..ec003ed 100644 --- a/dynamic_programming/digit_dp.cc +++ b/dynamic_programming/digit_dp.cc @@ -38,10 +38,15 @@ // for (int state = 0; state < M.size(); ++state) // if (M.accept(state)) oplusTo(ans, dp[n][tight][state]; // return ans; +// +// Here, tight means the left digits are tight so that the current +// digit cannot run over 0 to 9, and state means the state of the +// automaton, which compresses the 10^len states to |Automaton| states. // // Verified: // SPOJ_CPCRC1C // AOJ_ZIGZAG +// ABC_007D #include using namespace std; From af9a22a92953e903c474e98e79107103adbd0a53 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:09:56 +0900 Subject: [PATCH 105/141] Dijkstra Single Source Shortest Path --- graph/dijkstra.cc | 317 ++++++++++++++++++++++++++++++++++++++ graph/shortest_path_st.cc | 104 ------------- 2 files changed, 317 insertions(+), 104 deletions(-) create mode 100644 graph/dijkstra.cc delete mode 100644 graph/shortest_path_st.cc diff --git a/graph/dijkstra.cc b/graph/dijkstra.cc new file mode 100644 index 0000000..dfa4510 --- /dev/null +++ b/graph/dijkstra.cc @@ -0,0 +1,317 @@ +// +// Dijkstra's Single Source Shortest Path +// +// Description: +// +// Dijkstra algorithm finds a single source shortest path on +// a nonnegative weighted graph. +// It implements two algorithms with two data structures. +// (1) standard dijkstra with standard heap +// (2) bidirectional dijkstra with standard heap +// (3) standard dijkstra with radix heap +// (4) bidirectional dijkstra with radix heap +// +// For a simple test (see the code), we observe that +// Binomial,Unidirectional 14.74[s] +// Binomial Bidirectional 0.52[s] +// Radix,Unidirectional 4.90[s] +// Radix,Bidirectional 0.31[s] +// +// Complexity: +// +// O(m log n) for binomial heap +// O(m) for radix heap +// +// Verify: +// +// SPOJ_SHPATH (bidirectional search) +// +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +template +struct WeightedGraph { + struct Edge { + int to; + Weight weight; + }; + int n; + vector> adj, rdj; + WeightedGraph(int n) : n(n), adj(n), rdj(n) { } + void addEdge(int u, int v, Weight w) { + adj[u].push_back({v, w}); + rdj[v].push_back({u, w}); // can be omitted for the standard dijkstra + } +}; +template +struct ShortestPath { + WeightedGraph g; + ShortestPath(WeightedGraph g) : g(g), dist(g.n), prev(g.n) { } + + vector dist; + vector prev; + void solve(int s) { + prev.assign(g.n,-1); + dist.assign(g.n,-1); dist[s] = 0; + + using Node = pair; + priority_queue, greater> que; + que.push({0,s}); + while (!que.empty()) { + auto d = que.top().fst; + auto u = que.top().snd; + que.pop(); + if (dist[u] < d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u]+w) continue; + dist[v] = dist[u] + w; + prev[v] = u; + que.push({dist[v], v}); + } + } + } + int solve(int s, int t) { + if (s == t) return dist[s] = 0; + fill(all(dist), -1); dist[s] = 0; + vector drev(g.n, -1); drev[t] = 0; + + using Node = pair; + priority_queue, greater> qs, qt; + qs.push({0,s}); qt.push({0,t}); + int mu = -1; + while (!qs.empty() && !qt.empty()) { + if (mu >= 0 && qs.top().fst + qt.top().fst >= mu) break; + if (qs.top().fst <= qt.top().fst) { + auto d = qs.top().fst; + auto u = qs.top().snd; + qs.pop(); + if (dist[u] > d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u] + w) continue; + dist[v] = dist[u] + w; + qs.push({dist[v], v}); + if (drev[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } else { + auto d = qt.top().fst; + auto u = qt.top().snd; + qt.pop(); + if (drev[u] > d) continue; + for (auto e: g.rdj[u]) { + auto v = e.to; + auto w = e.weight; + if (drev[v] >= 0 && drev[v] <= drev[u] + w) continue; + drev[v] = drev[u] + w; + qt.push({drev[v], v}); + if (dist[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } + } + return mu; + } +}; + + +// +// Dijkstra with Radix Heap +// +template +struct RadixHeap { + using uint = uint32_t; // fix bit size + static int bsr(uint a) { return a ? 31 - __builtin_clz(a) : -1; } + uint size, last; + vector> v[33]; + RadixHeap() : size(0), last(0) { } + + bool empty() const { return size == 0; } + void aux(pair p) { v[bsr(p.fst^last)+1].push_back(p); } + pair top() { + if (v[0].empty()) { + int i = 1; + while (v[i].empty()) ++i; + last = min_element(all(v[i]))->fst; + for (auto p: v[i]) aux(p); + v[i].clear(); + } + return v[0].back(); + } + void push(uint key, T value) { ++size; aux({key, value}); } + void pop() { --size; top(); v[0].pop_back(); } +}; +template <> +struct ShortestPath { + using Weight = int; + WeightedGraph g; + + vector dist; + vector prev; + ShortestPath(WeightedGraph g) : g(g), dist(g.n), prev(g.n) { } + + void solve(int s) { + fill(all(prev), -1); + fill(all(dist), -1); dist[s] = 0; + + RadixHeap que; + que.push(0,s); + while (!que.empty()) { + auto d = que.top().fst; + auto u = que.top().snd; + que.pop(); + if (dist[u] < d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u]+w) continue; + dist[v] = dist[u] + w; + prev[v] = u; + que.push(dist[v], v); + } + } + } + // Bidirectional Dijkstra + int solve(int s, int t) { + if (s == t) return dist[s] = 0; + + fill(all(dist), -1); dist[s] = 0; + vector drev(g.n, -1); drev[t] = 0; + RadixHeap qs, qt; + qs.push(0,s); qt.push(0,t); + int mu = -1; + while (!qs.empty() && !qt.empty()) { + if (mu >= 0 && qs.top().fst + qt.top().fst >= mu) break; + if (qs.top().fst <= qt.top().fst) { + auto d = qs.top().fst; + auto u = qs.top().snd; + qs.pop(); + if (dist[u] > d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u] + w) continue; + dist[v] = dist[u] + w; + qs.push(dist[v], v); + if (drev[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } else { + auto d = qt.top().fst; + auto u = qt.top().snd; + qt.pop(); + if (drev[u] > d) continue; + for (auto e: g.rdj[u]) { + auto v = e.to; + auto w = e.weight; + if (drev[v] >= 0 && drev[v] <= drev[u] + w) continue; + drev[v] = drev[u] + w; + qt.push(drev[v], v); + if (dist[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } + } + return mu; + } +}; + +void SPOJ_SHPATH() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n; + scanf("%d", &n); + WeightedGraph g(n); + map id; + for (int u = 0; u < n; ++u) { + char name[1024]; + scanf("%s", name); + id[name] = u; + int k; + scanf("%d", &k); + for (int j = 0; j < k; ++j) { + int v, d; + scanf("%d %d", &v, &d); + g.addEdge(u, v-1, d); + } + } + ShortestPath solver(g); + int k; + scanf("%d", &k); + for (int i = 0; i < k; ++i) { + char s[1024], t[1024]; + scanf("%s %s", s, t); + printf("%d\n", solver.solve(id[s], id[t])); + } + } +} + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} +int test() { + int n = 5000; + WeightedGraph g(n); + for (int u = 0; u < n; ++u) { + int d = 1 + rand() % 30; + unordered_set N; + while (N.size() < d) { + int v = rand() % n; + if (u != v) N.insert(v); + } + for (auto v: N) { + int w = 1 + rand() % 10; + g.addEdge(u, v, w); + } + } + ShortestPath solver(g); + double t = 0; + for (int u = 0; u < n; ++u) { + int v = rand() % n; + tick(); + solver.solve(u); + int b = solver.dist[v]; + t += tick(); + } + cout << t << endl; + return true; +} + +int main() { + test(); +// SPOJ_SHPATH(); + /* + WeightedGraph g(3); + g.addEdge(0,1,10); + g.addEdge(0,2,20); + + ShortestPath solver(g); + solver.solve(0); + for (int u = 0; u < g.n; ++u) { + cout << solver.dist[u] << " "; + } + cout << endl; + */ +} diff --git a/graph/shortest_path_st.cc b/graph/shortest_path_st.cc deleted file mode 100644 index 1fbf1a9..0000000 --- a/graph/shortest_path_st.cc +++ /dev/null @@ -1,104 +0,0 @@ -// -// Single pair shortest path (Bidirectional dijkstra) -// -// Description: -// For a pair of vertices, it finds a shortest path between -// these two vertices. -// -// Algorithm: -// Bidirectional dijkstra algorithm that performs Dijkstra -// algorithm from s and t simultaneously. -// Usually, it is much faster than standard Dijkstra. -// -// Verified: -// SPOJ SHPATH -// -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -#define fst first -#define snd second - -const int INF = 99999999; -struct graph { - int n; - struct edge { int src, dst, weight; }; - vector> adj, rdj; - graph(int n) : n(n), adj(n), rdj(n) { } - void add_edge(int u, int v, int w) { - adj[u].push_back({u, v, w}); - rdj[v].push_back({v, u, w}); - } - - int shortest_path(int s, int t) { - if (s == t) return 0; - vector ds(n, INF), dt(n, INF); - typedef pair node; - priority_queue, greater> Qs, Qt; - Qs.push({ds[s] = 0, s}); - Qt.push({dt[t] = 0, t}); - int mu = INF; - while (!Qs.empty() && !Qt.empty()) { - if (Qs.top().fst + Qt.top().fst >= mu) break; - if (Qs.top().fst <= Qt.top().fst) { - node x = Qs.top(); Qs.pop(); - if (ds[x.snd] > x.fst) continue; - for (edge &e: adj[x.snd]) { - if (ds[e.src] + e.weight < ds[e.dst]) { - mu = min(mu, ds[e.src] + e.weight + dt[e.dst]); - Qs.push({ds[e.dst] = ds[e.src] + e.weight, e.dst}); - } - } - } else { - node x = Qt.top(); Qt.pop(); - if (dt[x.snd] > x.fst) continue; - for (edge &e: rdj[x.snd]) { - if (dt[e.src] + e.weight < dt[e.dst]) { - mu = min(mu, dt[e.src] + e.weight + ds[e.dst]); - Qt.push({dt[e.dst] = dt[e.src] + e.weight, e.dst}); - } - } - } - } - return mu; - } -}; - - -void solve() { - int n; - scanf("%d", &n); - graph g(n); - map id; - for (int u = 0; u < n; ++u) { - char name[1024]; - scanf("%s", name); - id[name] = u; - int k; - scanf("%d", &k); - for (int j = 0; j < k; ++j) { - int v, d; - scanf("%d %d", &v, &d); - g.add_edge(u, v-1, d); - } - } - int k; - scanf("%d", &k); - for (int i = 0; i < k; ++i) { - char s[1024], t[1024]; - scanf("%s %s", s, t); - printf("%d\n", g.shortest_path(id[s], id[t])); - } -} - -int main() { - int ncase; scanf("%d", &ncase); - for (int icase = 0; icase < ncase; ++icase) solve(); -} From a810c3f304ac79daf15376ea6f13ec3b1e786955 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:20:50 +0900 Subject: [PATCH 106/141] radix_heap.cc --- data_structure/radix_heap.cc | 182 ++++++++++++++++++++++++++++++----- 1 file changed, 160 insertions(+), 22 deletions(-) diff --git a/data_structure/radix_heap.cc b/data_structure/radix_heap.cc index 9685dfc..b23e526 100644 --- a/data_structure/radix_heap.cc +++ b/data_structure/radix_heap.cc @@ -1,9 +1,30 @@ -#include -#include -#include -#include -#include -#include +// +// Radix Heap +// +// Description: +// +// A radix heap is a heap for keys of type unsigned int. +// It runs in O(bit) time for each operations with a +// smaller constant factor. It is useful in Dijkstra +// shortest path algorithm with integral edge weights. +// see: https://en.wikipedia.org/wiki/Radix_heap +// +// Complexity: +// +// O(|bit|) per operations. +// +// Verified: +// +// SPOJ_SHPATH +// +// References: +// +// B. V. Cherkassky, A. V. Goldberg, C. Silverstein (1997): +// "Buckets, Heaps, Lists and Monotone Priority Queues." +// in Proceedings of the 8th Annual ACM-SIAM Symposium on +// Discrete Algorithms (SODA'97), pp. 83-92. +// +#include using namespace std; @@ -12,23 +33,23 @@ using namespace std; #define all(c) ((c).begin()), ((c).end()) #define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } -// min heap +// Min Heap template -struct radix_heap { - typedef unsigned int uint; +struct RadixHeap { + using uint = uint32_t; // fix bit size static int bsr(uint a) { return a ? 31 - __builtin_clz(a) : -1; } uint size, last; vector> v[33]; - radix_heap() : size(0), last(0) { } + RadixHeap() : size(0), last(0) { } bool empty() const { return size == 0; } - void aux(const pair &p) { v[bsr(p.fst^last)+1].push_back(p); } + void aux(pair p) { v[bsr(p.fst^last)+1].push_back(p); } pair top() { if (v[0].empty()) { int i = 1; while (v[i].empty()) ++i; last = min_element(all(v[i]))->fst; - for (auto &p: v[i]) aux(p); + for (auto p: v[i]) aux(p); v[i].clear(); } return v[0].back(); @@ -37,15 +58,132 @@ struct radix_heap { void pop() { --size; top(); v[0].pop_back(); } }; -int main() { - radix_heap heap; - heap.push(strlen("test"), "test"); - heap.push(strlen("a"), "a"); - heap.push(strlen("ab"), "ab"); - heap.push(strlen("aaa"), "aaa"); - heap.push(strlen("xyzz"), "xyzz"); - while (!heap.empty()) { - cout << heap.top().snd << endl; - heap.pop(); +template +struct WeightedGraph { + struct Edge { + int to; + Weight weight; + }; + int n; + vector> adj, rdj; + WeightedGraph(int n) : n(n), adj(n), rdj(n) { } + void addEdge(int u, int v, Weight w) { + adj[u].push_back({v, w}); + rdj[v].push_back({u, w}); // can be omitted for the standard dijkstra + } +}; + +template +struct ShortestPath { }; // omit + +template <> +struct ShortestPath { + using Weight = int; + WeightedGraph g; + + vector dist; + vector prev; + ShortestPath(WeightedGraph g) : g(g), dist(g.n), prev(g.n) { } + + void solve(int s) { + fill(all(prev), -1); + fill(all(dist), -1); dist[s] = 0; + + RadixHeap que; + que.push(0,s); + while (!que.empty()) { + auto d = que.top().fst; + auto u = que.top().snd; + que.pop(); + if (dist[u] < d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u]+w) continue; + dist[v] = dist[u] + w; + prev[v] = u; + que.push(dist[v], v); + } + } } + // Bidirectional Dijkstra + int solve(int s, int t) { + if (s == t) return dist[s] = 0; + + fill(all(dist), -1); dist[s] = 0; + vector drev(g.n, -1); drev[t] = 0; + RadixHeap qs, qt; + qs.push(0,s); qt.push(0,t); + int mu = -1; + while (!qs.empty() && !qt.empty()) { + if (mu >= 0 && qs.top().fst + qt.top().fst >= mu) break; + if (qs.top().fst <= qt.top().fst) { + auto d = qs.top().fst; + auto u = qs.top().snd; + qs.pop(); + if (dist[u] > d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u] + w) continue; + dist[v] = dist[u] + w; + qs.push(dist[v], v); + if (drev[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } else { + auto d = qt.top().fst; + auto u = qt.top().snd; + qt.pop(); + if (drev[u] > d) continue; + for (auto e: g.rdj[u]) { + auto v = e.to; + auto w = e.weight; + if (drev[v] >= 0 && drev[v] <= drev[u] + w) continue; + drev[v] = drev[u] + w; + qt.push(drev[v], v); + if (dist[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } + } + return mu; + } +}; + +void SPOJ_SHPATH() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n; + scanf("%d", &n); + WeightedGraph g(n); + map id; + for (int u = 0; u < n; ++u) { + char name[1024]; + scanf("%s", name); + id[name] = u; + int k; + scanf("%d", &k); + for (int j = 0; j < k; ++j) { + int v, d; + scanf("%d %d", &v, &d); + g.addEdge(u, v-1, d); + } + } + ShortestPath solver(g); + int k; + scanf("%d", &k); + for (int i = 0; i < k; ++i) { + char s[1024], t[1024]; + scanf("%s %s", s, t); + printf("%d\n", solver.solve(id[s], id[t])); + } + } +} +int main() { + SPOJ_SHPATH(); } From ce25bade1e3388d5a7a79f2686a0263da957a9b9 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:28:09 +0900 Subject: [PATCH 107/141] Radix Heap --- data_structure/radix_heap.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/data_structure/radix_heap.cc b/data_structure/radix_heap.cc index b23e526..16c9b33 100644 --- a/data_structure/radix_heap.cc +++ b/data_structure/radix_heap.cc @@ -3,15 +3,16 @@ // // Description: // -// A radix heap is a heap for keys of type unsigned int. -// It runs in O(bit) time for each operations with a -// smaller constant factor. It is useful in Dijkstra -// shortest path algorithm with integral edge weights. +// A radix heap is a monotonic heap for keys of type unsigned int. +// Here, a monotonic heap is a heap that allows push(key) only for +// key >= top(). It is useful in the Dijkstra shortest path algorithm +// with integral edge weights. // see: https://en.wikipedia.org/wiki/Radix_heap // // Complexity: // -// O(|bit|) per operations. +// O(|bit|) for all operations. Moreover, +// O(1), amortized, for pop. // // Verified: // From f8c90281baef8950ec1b484507dce64ed6e2f92b Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:37:09 +0900 Subject: [PATCH 108/141] Numerical Differentiation --- numerical/derivative.cc | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 numerical/derivative.cc diff --git a/numerical/derivative.cc b/numerical/derivative.cc new file mode 100644 index 0000000..9b700bd --- /dev/null +++ b/numerical/derivative.cc @@ -0,0 +1,58 @@ +// +// Numerical Derivative by Ridder's method. +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +double differentiate(F f, double x, double eps = 1e-8) { + const int n = 10; + const double alpha = 1.4; + double h = 1e-2, a[n][n], ans = 1.0/0.0, err = 1.0/0.0; + + a[0][0] = (f(x + h) - f(x - h)) / (2 * h); + for (int i = 1; i < n; ++i) { + h /= alpha; + a[0][i] = (f(x + h) - f(x - h))/(2 * h); + double fac = alpha * alpha; + for (int j = 1; j <= i; ++j) { + a[j][i] = (a[j-1][i] * fac - a[j-1][i-1])/(fac - 1.0); + fac *= alpha * alpha; + double errt = max(fabs(a[j][i] - a[j-1][i]), fabs(a[j][i] - a[j-1][i-1])); + if (errt <= err) { + err = errt; + ans = a[j][i]; + if (err < eps) return ans; + } + } + if (fabs(a[i][i] - a[i-1][i-1]) >= 2 * err) break; + } + return ans; +} + +double f(double x) { + return exp(-x*x); +} +double df(double x) { + return -2 * x * exp(-x*x); +} + +int main() { + for (int i = 0; i < 10; ++i) { + double x = rand() / (1.0 + RAND_MAX); + cout << differentiate(f, x) - df(x) << endl; + } +} + From 4050b9aec396e1381e6a65853c67e64fd7fe096a Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:38:08 +0900 Subject: [PATCH 109/141] Numerical Differentiation --- {numerical => numeric}/derivative.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {numerical => numeric}/derivative.cc (100%) diff --git a/numerical/derivative.cc b/numeric/derivative.cc similarity index 100% rename from numerical/derivative.cc rename to numeric/derivative.cc From 54eff6e49df09bf337975d40c90c5b3e5961e541 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:38:42 +0900 Subject: [PATCH 110/141] Ordinal Differential Equation (Dormand-Prince) --- {math => numeric}/ODE_dormand_prince.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => numeric}/ODE_dormand_prince.cc (100%) diff --git a/math/ODE_dormand_prince.cc b/numeric/ODE_dormand_prince.cc similarity index 100% rename from math/ODE_dormand_prince.cc rename to numeric/ODE_dormand_prince.cc From 9a3ab6aa375603dda63885f38451c9e521c7c55b Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:39:09 +0900 Subject: [PATCH 111/141] Ordinal Differential Equation (Runge Kutta) --- {math => numeric}/ODE_runge_kutta.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => numeric}/ODE_runge_kutta.cc (100%) diff --git a/math/ODE_runge_kutta.cc b/numeric/ODE_runge_kutta.cc similarity index 100% rename from math/ODE_runge_kutta.cc rename to numeric/ODE_runge_kutta.cc From f2f0cb20608bbc5469a3100ef0fea678f86a3cb6 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:39:30 +0900 Subject: [PATCH 112/141] Delete derivative.cc --- math/derivative.cc | 58 ---------------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 math/derivative.cc diff --git a/math/derivative.cc b/math/derivative.cc deleted file mode 100644 index 9b700bd..0000000 --- a/math/derivative.cc +++ /dev/null @@ -1,58 +0,0 @@ -// -// Numerical Derivative by Ridder's method. -// - -#include -#include -#include -#include -#include -#include - -using namespace std; - -#define fst first -#define snd second -#define all(c) ((c).begin()), ((c).end()) -#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } - -template -double differentiate(F f, double x, double eps = 1e-8) { - const int n = 10; - const double alpha = 1.4; - double h = 1e-2, a[n][n], ans = 1.0/0.0, err = 1.0/0.0; - - a[0][0] = (f(x + h) - f(x - h)) / (2 * h); - for (int i = 1; i < n; ++i) { - h /= alpha; - a[0][i] = (f(x + h) - f(x - h))/(2 * h); - double fac = alpha * alpha; - for (int j = 1; j <= i; ++j) { - a[j][i] = (a[j-1][i] * fac - a[j-1][i-1])/(fac - 1.0); - fac *= alpha * alpha; - double errt = max(fabs(a[j][i] - a[j-1][i]), fabs(a[j][i] - a[j-1][i-1])); - if (errt <= err) { - err = errt; - ans = a[j][i]; - if (err < eps) return ans; - } - } - if (fabs(a[i][i] - a[i-1][i-1]) >= 2 * err) break; - } - return ans; -} - -double f(double x) { - return exp(-x*x); -} -double df(double x) { - return -2 * x * exp(-x*x); -} - -int main() { - for (int i = 0; i < 10; ++i) { - double x = rand() / (1.0 + RAND_MAX); - cout << differentiate(f, x) - df(x) << endl; - } -} - From e48dcd84c51378ee2df0197ca3ba7e56709b1400 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:40:33 +0900 Subject: [PATCH 113/141] Assignment Problem (Jonker-Volgenant) --- {math => numeric}/assignment.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => numeric}/assignment.cc (100%) diff --git a/math/assignment.cc b/numeric/assignment.cc similarity index 100% rename from math/assignment.cc rename to numeric/assignment.cc From 249fe566326553a5c370c4c9c226d0d43edb2859 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:41:36 +0900 Subject: [PATCH 114/141] Numerical Integrator (Adaptive Gauss-Lobatto) --- {math => numeric}/integrate.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => numeric}/integrate.cc (100%) diff --git a/math/integrate.cc b/numeric/integrate.cc similarity index 100% rename from math/integrate.cc rename to numeric/integrate.cc From 7f295461723c0fc939a7937d40a196889dc92ec6 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:42:31 +0900 Subject: [PATCH 115/141] Numerical Integrator (Double Exponential) --- {math => numeric}/integrate_DE.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => numeric}/integrate_DE.cc (100%) diff --git a/math/integrate_DE.cc b/numeric/integrate_DE.cc similarity index 100% rename from math/integrate_DE.cc rename to numeric/integrate_DE.cc From c3c80f8ea0038b735d2d0b07743925b6083a9b71 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:44:25 +0900 Subject: [PATCH 116/141] Goldensection Search for 1D Unimodal Minimization --- {math => numeric}/find_min_unimodal.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => numeric}/find_min_unimodal.cc (100%) diff --git a/math/find_min_unimodal.cc b/numeric/find_min_unimodal.cc similarity index 100% rename from math/find_min_unimodal.cc rename to numeric/find_min_unimodal.cc From 9cf6552460342fd277c74c696b471760a848ef5c Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:45:44 +0900 Subject: [PATCH 117/141] Nelder Mead Method for Non-convex Minimization --- {math => numeric}/nelder_mead.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {math => numeric}/nelder_mead.cc (98%) diff --git a/math/nelder_mead.cc b/numeric/nelder_mead.cc similarity index 98% rename from math/nelder_mead.cc rename to numeric/nelder_mead.cc index f48bb0d..bd24796 100644 --- a/math/nelder_mead.cc +++ b/numeric/nelder_mead.cc @@ -2,7 +2,7 @@ // Nelder Mead method (aka. Downhill Simplex Method) // // Description: -// Nelder Mead method is a first-order optimization method +// Nelder Mead method is a zeroth-order optimization method // that only requires function evaluation oracle. // Typically, it performs well on a function on a small // dimensional space. From 0890ecc39e2911334d17fee4fd2c28cc680243cd Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:46:33 +0900 Subject: [PATCH 118/141] Automatic Differentiation by Dual Numbers --- {math => numeric}/dual_number.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => numeric}/dual_number.cc (100%) diff --git a/math/dual_number.cc b/numeric/dual_number.cc similarity index 100% rename from math/dual_number.cc rename to numeric/dual_number.cc From 954491aca85b3bf6911174554ce9a521267d356e Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 14 Jan 2018 22:53:53 +0900 Subject: [PATCH 119/141] Chebyshev Approximation --- numeric/chebyshev.cc | 125 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 numeric/chebyshev.cc diff --git a/numeric/chebyshev.cc b/numeric/chebyshev.cc new file mode 100644 index 0000000..c2b5b0e --- /dev/null +++ b/numeric/chebyshev.cc @@ -0,0 +1,125 @@ +// +// Chebyshev approximation of smooth function +// +// Description: +// +// Given a smooth function f: [0,1] -> R. It approximates f by +// f(x) \sim p(x) := sum_{k=0}^{n-1} ck Tk(x) +// where Tk(x) is the Chebyshev polynomial of the first kind: +// Tk(cos(u)) = cos(ku). +// This almost minimizes the maximum error: +// sup_x | f(x) - p(x) | +// This also provides accurate dp/dx and \int_{a^x} p(u) du. +// +// We can construct the Chebyshev approximation in O(n^2) time +// by using the orthogonality with Clenshow's relation. +// +// Complexity: +// +// O(n^2), where n is usually 10--30. +// +// References: +// +// C. W. Clenshaw (1995): +// "A note on the summation of Chebyshev series." +// Mathematical Tables and Other Aids to Computation. +// vol.9, no.51, pp.118--120. +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Real = long double; +struct Chebyshev { + static constexpr Real PI = acos(-1.0); + int n; + Real a, b; + vector c; + Chebyshev(Real a, Real b, int n) : n(n), a(a), b(b), c(n) { } + + template + Chebyshev(F f, Real a, Real b, int n = 20) : n(n), a(a), b(b), c(n) { + vector h(n); + for (int k = 0; k < n; ++k) { + Real y = cos(PI*(k+0.5)/n); + h[k] = f((b-a)/2*y + (b+a)/2); + } + for (int j = 0; j < n; ++j) { + for (int k = 0; k < n; ++k) + c[j] += h[k] * cos(PI*j*(k+0.5)/n); + c[j] *= 2.0/n; + } + } + Real operator()(Real x) const { + Real y = (2*x - a-b)/(b-a), u = 0, v = 0; + for (int j = n-1; j >= 1; --j) { + Real w = 2*y*u - v + c[j]; + v = u; u = w; + } + return y*u - v + 0.5*c[0]; + } +}; +Chebyshev differentiate(Chebyshev f) { + Chebyshev g = f; + g.c[f.n-2] = 2 * (f.n-1) * f.c[f.n-1]; + for (int j = f.n-3; j >= 0; --j) + g.c[j] = g.c[j+2] + 2 * (j+1) * f.c[j+1]; + for (int j = 0; j < g.n; ++j) + g.c[j] *= 2.0/(g.b - g.a); + return g; +} +Chebyshev integrate(Chebyshev f) { + Chebyshev g = f; + Real sum = 0, coef = (f.b-f.a)/4, sign = 1.0; + for (int j = 1; j <= g.n-2; ++j) { + g.c[j] = coef * (f.c[j-1] - f.c[j+1]) / j; + sum += sign * g.c[j]; + sign = -sign; + } + g.c[f.n-1] = coef * f.c[f.n-2] / (f.n-1); + sum += sign * g.c[f.n-1]; + g.c[0] = 2 * sum; + return g; +} + +int main() { + auto f = [&](Real x) { + return sqrt(1 + x*x); + }; + auto df = [&](Real x) { + return x / sqrt(1 + x*x); + }; + auto F = [&](Real x) { + return (x*sqrt(1 + x*x) + asinh(x))/2; + }; + Chebyshev g(f, 0, 1, 10); + Chebyshev dg = differentiate(g); + Chebyshev G = integrate(g); + + cout << "---" << endl; + for (int i = 0; i < 10; ++i) { + Real u = i / 10.0; + cout << f(u) - g(u) << endl; + } + cout << "---" << endl; + for (int i = 0; i < 10; ++i) { + Real u = i / 10.0; + cout << df(u) - dg(u) << endl; + } + cout << "---" << endl; + for (int i = 0; i < 10; ++i) { + Real u = i / 10.0; + cout << F(u) - G(u) << endl; + } +} From b74dffcead5ca26b7f4fd0a1b6515c5d1669943c Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 27 Jan 2018 14:46:25 +0900 Subject: [PATCH 120/141] Parallel Binary Search --- data_structure/parallel_binary_search.cc | 149 +++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 data_structure/parallel_binary_search.cc diff --git a/data_structure/parallel_binary_search.cc b/data_structure/parallel_binary_search.cc new file mode 100644 index 0000000..1323f80 --- /dev/null +++ b/data_structure/parallel_binary_search.cc @@ -0,0 +1,149 @@ +// +// Parallel Binary Search +// +// Description: +// +// Let W(t) be a data structure depending on time t. +// Suppose that there are n agents. Each agent j wants to +// find the smallest time t(j) such that cond(j, W(t(j))) == true +// where cond(j, W(t)) is monotone in t. +// +// If we perform n binary searches independently, we will construct +// W(t) multiple times. Thus, we avoid the redundant construction +// by performing n binary searches in parallel. Imagine a binary +// search tree on t. For each node, we first construct W(t). +// Then we process multiple agents in parallel. Then, the total +// number of constructions is O(log T), which is independent to +// the number of agents. +// +// Complexity: +// +// Suppose that W(t) is constructed from W(t') in time M(|t-t'|), +// and the condition cond(j,W(t)) is evaluated in time Q. +// Then, it runs in O(M(T log T) + n Q log T) time. +// +// Even if W does not have decremental operations, i.e., W(t) +// cannot be constructed from W(t') with t' > t, we can still use +// the parallel binary search that runs in O(M(T) log T + n Q log T); +// time. The constant factor is twice worse than the above. +// Similar result holds if W does not have incremental operations. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Int = __int128_t; + +// Point Query, Range Update +template +struct FenwickTree { + vector x; + FenwickTree(int n) : x(n) { } + void add(int k, T a) { // aux + for (; k < x.size(); k |= k+1) x[k] += a; + } + void add(int i, int j, T a) { // add x[k] += a for all k in [i,j] + add(i, a); + if (j+1 < x.size()) add(j+1, -a); + } + T get(int k) { // return x[k] + T sum = 0; + for (; k >= 0; k = (k&(k+1))-1) sum += x[k]; + return sum; + } +}; + +template +vector parallelBinarySearch( + int n, int lo, int hi, Update update, Cond cond) { + using It = vector::iterator; + vector agents(n), solution(n, lo); + iota(all(agents), 0); + + It begin = agents.begin(), end = agents.end(); + deque> stack = {make_tuple(lo, hi, begin, end)}; + while (!stack.empty()) { + // invariant: elems in [begin, end) satisfy "!cond(lo) and cond(hi)" + tie(lo, hi, begin, end) = stack.back(); + stack.pop_back(); + + if (begin == end) continue; + if (lo+1 == hi) { + for_each(begin, end, [&](int k) { solution[k] = hi; }); + continue; + } + int mi = (lo + hi) / 2; + update(mi); + It mid = partition(begin, end, [&](int k) { return cond(k); }); + stack.push_back(make_tuple(mi, hi, mid, end)); + stack.push_back(make_tuple(lo, mi, begin, mid)); + } + return solution; +} + +void SPOJ_METEORS() { + int n, m, k; + scanf("%d %d", &n, &m); + vector> S(n); + vector p(n); + for (int i = 0; i < m; ++i) { + int j; scanf("%d", &j); + S[j-1].push_back(i); + } + for (int i = 0; i < n; ++i) + scanf("%lld", &p[i]); + scanf("%d", &k); + vector l(k), r(k); + vector a(k); + for (int i = 0; i < k; ++i) { + scanf("%d %d %lld", &l[i], &r[i], &a[i]); + --l[i]; --r[i]; + } + + FenwickTree FT(m); + int curr = -1; + auto update = [&](int time) { + while (curr < time) { + ++curr; + if (l[curr] <= r[curr]) { + FT.add(l[curr], r[curr], a[curr]); + } else { + FT.add(l[curr], m-1, a[curr]); + FT.add(0, r[curr], a[curr]); + } + } + while (curr > time) { + if (l[curr] <= r[curr]) { + FT.add(l[curr], r[curr], -a[curr]); + } else { + FT.add(l[curr], m-1, -a[curr]); + FT.add(0, r[curr], -a[curr]); + } + --curr; + } + }; + // minimum time such that cond = true. + auto cond = [&](int j) { + Int total = 0; + for (int i: S[j]) { + total += FT.get(i); + } + return total >= p[j]; + }; + + auto solution = parallelBinarySearch(n, -1, k, update, cond); + + for (int i = 0; i < n; ++i) { + if (solution[i] >= k) cout << "NIE" << endl; + else cout << 1+solution[i] << endl; + } +} + +int main() { + SPOJ_METEORS(); +} From b541e0b06aa4145592527b7de8e2caa8720bac22 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 28 Jan 2018 09:19:38 +0900 Subject: [PATCH 121/141] Bjorklund-Husfield's exact chromatic number --- graph/chromatic_number.cc | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 graph/chromatic_number.cc diff --git a/graph/chromatic_number.cc b/graph/chromatic_number.cc new file mode 100644 index 0000000..aef4837 --- /dev/null +++ b/graph/chromatic_number.cc @@ -0,0 +1,96 @@ +// +// Exact Algorithm for Chromatic Number +// +// Description: +// +// A vertex coloring is an assignment of colors to the vertices +// such that no adjacent vertices have a same color. The smallest +// number of colors for a vertex coloring is called the chromatic +// number. Computing the chromatic number is NP-hard. +// +// We can compute the chromatic number by the inclusion-exlusion +// principle. The complexity is O(poly(n) 2^n). The following +// implementation runs in O(n 2^n) but is a Monte-Carlo algorithm +// since it takes modulos to avoid multiprecision numbers. +// +// Complexity: +// +// O(n 2^n) +// +// References: +// +// Andreas Bjorklund and Thore Husfeldt (2006): +// "Inclusion--Exclusion Algorithms for Counting Set Partitions." +// in Proceedings of the 47th Annual Symposium on Foundations of +// Computer Science, pp. 575--582. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Graph { + int n; + vector> adj; + Graph(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); + } +}; + +int chromaticNumber(Graph g) { + const int N = 1 << g.n; + vector nbh(g.n); + for (int u = 0; u < g.n; ++u) + for (int v: g.adj[u]) + nbh[u] |= (1 << v); + + int ans = g.n; + for (int d: {7}) { // ,11,21,33,87,93}) { + long long mod = 1e9 + d; + vector ind(N), aux(N, 1); + ind[0] = 1; + for (int S = 1; S < N; ++S) { + int u = __builtin_ctz(S); + ind[S] = ind[S^(1<> 1); // gray-code + aux[S] = (aux[S] * ind[S]) % mod; + chi += (i & 1) ? aux[S] : -aux[S]; + } + if (chi % mod) ans = k; + } + } + return ans; +} + +int main() { + int n = 6; + Graph g(n); + g.addEdge(0,1); + g.addEdge(1,2); + g.addEdge(2,3); + g.addEdge(0,2); + g.addEdge(3,4); + g.addEdge(4,5); + g.addEdge(5,0); + // 0 + // 1 5 + // + // 2 4 + // 3 + /* + for (int i = 0; i < n; ++i) + for (int j = 0; j < i; ++j) + g.addEdge(i, j); + */ + cout << chromaticNumber(g) << endl; +} From 73aab4cd5d92c370049d3c55fd8ebacb67554476 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 28 Jan 2018 17:48:10 +0900 Subject: [PATCH 122/141] Modular Arithmetics --- math/modular_arithmetics.cc | 467 ++++++++++++++++++++++++++++++++++++ 1 file changed, 467 insertions(+) create mode 100644 math/modular_arithmetics.cc diff --git a/math/modular_arithmetics.cc b/math/modular_arithmetics.cc new file mode 100644 index 0000000..70d495a --- /dev/null +++ b/math/modular_arithmetics.cc @@ -0,0 +1,467 @@ +// +// Modular Arithmetics +// +// long long: 10^18 < 2^63-1 < 10^19 (strict inequality) +// __int128_t: 10^38 < 2^127-1 < 10^39 +// +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include +#pragma GCC optimize ("O3") + +using namespace std; +#define fst first +#define snd second +#define all(c) begin(c), end(c) + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + + +template +ostream &operator<<(ostream &os, const vector &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << " "; + os << "]"; + return os; +} +template +ostream &operator<<(ostream &os, const vector> &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << endl << " "; + os << "]"; + return os; +} +using Int = long long; +struct ModInt { + Int val, mod; + ModInt(Int v, Int m) : val(v), mod(m) { } + ModInt operator-() const { return ModInt(val?mod-val:val,mod); } + ModInt &operator+=(ModInt a) { + if ((val += a.val) >= mod) val -= mod; + return *this; + } + ModInt &operator-=(ModInt a) { + if ((val -= a.val) < 0) val += mod; + return *this; + } + ModInt &operator*=(ModInt a) { + val = (__uint128_t(val) * a.val) % mod; + return *this; + } + ModInt &operator/=(ModInt a) { + Int u = 1, v = a.val, s = 0, t = mod; + while (v) { + Int q = t / v; + swap(s -= u * q, u); + swap(t -= v * q, v); + } + a.val = (s < 0 ? s + mod : s); + val /= t; + return (*this) *= a; + } + ModInt inv() const { return ModInt(1,mod) /= (*this); } + bool operator<(ModInt x) const { return val < x.val; } +}; +// ModInt modInt(Int v) { return ModInt(v,MOD); } +ostream &operator<<(ostream &os, ModInt a) { os << a.val; return os; } +ModInt operator+(ModInt a, ModInt b) { return a += b; } +ModInt operator-(ModInt a, ModInt b) { return a -= b; } +ModInt operator*(ModInt a, ModInt b) { return a *= b; } +ModInt operator/(ModInt a, ModInt b) { return a /= b; } +ModInt pow(ModInt a, Int e) { + ModInt x(1, a.mod); + for (; e > 0; e /= 2) { + if (e % 2 == 1) x *= a; + a *= a; + } + return x; +} +ModInt stringToModInt(string s, Int mod) { + Int val = 0; + for (int i = 0; i < s.size(); ++i) + val = (val*10 + (s[i]-'0')) % mod; + return ModInt(val, mod); +} + + +// compute inv[1], inv[2], ..., inv[mod-1] in O(n) time +vector inverse(Int mod) { + vector inv(mod, ModInt(0, mod)); + inv[1] = 1; + for (Int a = 2; a < mod; ++a) + inv[a] = inv[mod % a] * (mod - mod/a); + return inv; +} + + +// +// Solve x^2 = n; mod should be a prime +// +// Verified: Code Forces Quadratic Equations +// +bool isQuadraticResidue(ModInt n) { + return n.val == 0 || n.mod == 2 || pow(n, (n.mod-1)/2).val == 1; +} +ModInt sqrt(ModInt n) { + if (n.val == 0 || n.mod == 2) return n; + int M = __builtin_ctz(n.mod-1), Q = (n.mod-1)>>M; + ModInt z(2, n.mod); + while (isQuadraticResidue(z)) ++z.val; + ModInt c = pow(z, Q); + ModInt t = pow(n, Q); + ModInt R = pow(n, (Q+1)/2); + while (t.val != 1) { + int i = 0; + for (ModInt s = t; s.val != 1; s *= s) ++i; + if (M == i) exit(0); + ModInt b = pow(c, 1<<(M-i-1)); + M = i; + c = b*b; + t *= c; + R *= b; + } + return R; +} +vector quadraticEquation(ModInt a, ModInt b, ModInt c) { + if (a.mod == 2) { + vector ans; + if (c.val == 0) ans.push_back(c); + if ((a + b + c).val == 0) ans.push_back(ModInt(1,2)); + return ans; + } else { + b /= (a+a); c /= a; + ModInt D = b*b - c; + if (!isQuadraticResidue(D)) return {}; + ModInt s = sqrt(D), x = -b+s, y = -b-s; + return (x.val < y.val) ? vector({x, y}) : + (x.val > y.val) ? vector({y, x}) : + vector({x}); + } +} + +// Discrete Logarithm by Shanks' Baby-Step Giant-Step +// +// Find k such that a^k == b +// +Int log(ModInt a, ModInt b) { + Int h = ceil(sqrt(a.mod+1e-9)); + unordered_map hash; + ModInt x(1, a.mod); + for (Int i = 0; i < h; ++i) { + if (!hash.count(x.val)) hash[x.val] = i; + x *= a; + } + x = x.inv(); + ModInt y = b; + for (int i = 0; i < h; ++i) { + if (hash.count(y.val)) return i*h+hash[y.val]; + y *= x; + } + return -1; +} + + +// +// find solution z.val such that +// z.val == x.val (mod x.mod), for all x. +// the solution is unique in modulo z.mod. +// +Int extgcd(Int a, Int b, Int&x, Int&y) { + for (Int u = y = 1, v = x = 0; a; ) { + Int q = b / a; + swap(x -= q * u, u); + swap(y -= q * v, v); + swap(b -= q * a, a); + } + return b; // a x + b y == gcd(a, b) +} +ModInt chineseRemainder(vector modular) { + ModInt z(0, 1); // z == 0 (mod 1) + for (ModInt x: modular) { + Int u, v, g = extgcd(x.mod, z.mod, u, v); + z.val = z.val*u*x.mod + x.val*v*z.mod; + z.mod = z.mod * (x.mod / g); + } + if ((z.val %= z.mod) < 0) z.val += z.mod; + return z; +} + +struct ModMatrix { + int m, n; // m times n matrix + vector> val; + Int mod; + ModInt &operator()(int i, int j) { return val[i][j]; } + ModMatrix(int m, int n, Int mod) : + m(m), n(n), mod(mod), val(m, vector(n, ModInt(0,mod))) { } + ModMatrix operator-() const { + ModMatrix A(m, n, mod); + for (int i = 0; i < m; ++i) + for (int j = 0; j < n; ++j) + A.val[i][j] = -val[i][j]; + return A; + } + ModMatrix &operator+=(ModMatrix A) { + for (int i = 0; i < m; ++i) + for (int j = 0; j < n; ++j) + val[i][j] += A.val[i][j]; + return *this; + } + ModMatrix &operator-=(ModMatrix A) { + for (int i = 0; i < m; ++i) + for (int j = 0; j < n; ++j) + val[i][j] -= A.val[i][j]; + return *this; + } + ModMatrix &operator*=(ModMatrix A) { + for (int i = 0; i < m; ++i) { + vector row(A.n, ModInt(0, A.mod)); + for (int j = 0; j < A.n; ++j) { + for (int k = 0; k < A.m; ++k) + row[j] += val[i][k] * A.val[k][j]; + } + val[i] = row; + } + return *this; + } + static ModMatrix eye(int n, Int mod) { + ModMatrix I(n, n, mod); + for (int i = 0; i < n; ++i) I.val[i][i].val = 1; + return I; + } + static ModMatrix zero(int n, Int mod) { + return ModMatrix(n, n, mod); + } + // Gauss-Jordan-Blankinship Elimination + // It can be used for any composite modulo (Euclidean domain). + ModMatrix inv() const { + ModMatrix B = eye(n, mod); + vector> a = val; + vector> &b = B.val; + for (int j = 0; j < n; ++j) { + // minimum nonzero をとって + // Blankinship type の吐き出しを行う + for (int i = 0; i < n; ++i) { + if (i == j) continue; + while (a[i][j].val) { + ModInt t(a[j][j].val/a[i][j].val, mod); + for (int k = j; k < n; ++k) swap(a[i][k], a[j][k]-=t*a[i][k]); + for (int k = 0; k < n; ++k) swap(b[i][k], b[j][k]-=t*b[i][k]); + } + } + if (a[j][j].val == 0) return ModMatrix(0,0,0); + } + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + cout << a[i][j] << " "; + } + cout << endl + } + + return B; + } + // It can be used for any composite modulo. + ModInt det() const { + vector> a = val; + ModInt D(1, mod); + for (int j = 0; j < n; ++j) { + for (int i = j+1; i < n; ++i) { + while (a[i][j].val) { + D = -D; + ModInt t(a[j][j].val/a[i][j].val, mod); + for (int k = j; k < n; ++k) + swap(a[i][k], a[j][k] -= t * a[i][k]); + } + } + D *= a[j][j]; + } + return D; + } +}; +ModMatrix operator+(ModMatrix A, ModMatrix B) { return A += B; } +ModMatrix operator-(ModMatrix A, ModMatrix B) { return A -= B; } +ModMatrix operator*(ModMatrix A, ModMatrix B) { return A *= B; } +ModMatrix pow(ModMatrix A, int k) { + ModMatrix X = ModMatrix::eye(A.n, A.mod); + for (; k > 0; k /= 2) { + if (k % 2 == 1) X *= A; + A *= A; + } + return X; +} +ModInt dot(ModMatrix A, ModMatrix B) { + ModInt val(0, A.mod); + for (int i = 0; i < A.m; ++i) + for (int j = 0; j < A.n; ++j) + val += A.val[i][j] * B.val[i][j]; + return val; +} +using ModVector = vector; +ModVector operator*(ModMatrix A, ModVector x) { + vector y(A.m, ModInt(0, A.mod)); + for (int i = 0; i < A.m; ++i) + for (int j = 0; j < A.n; ++j) + y[i] += A.val[i][j] * x[j]; + return y; +} + + +// +// Only available for prime modulos. +// If you want to compute multiple inverses, +// use LU decomposition instead of computing the inverse. +// +struct LUDecomposition { + int n; + vector pi; + vector> val; + Int mod; + LUDecomposition(ModMatrix A) : n(A.n), val(A.val), mod(A.mod) { + pi.resize(n+1); + iota(all(pi), 0); + for (int i = 0, j, k; i < n; ++i) { + for (k = i; k < n; ++k) + if (val[k][i].val) break; + if (k == n) { pi[n] = -1; return; } // NG + if (k != i) { + swap(pi[i], pi[k]); + swap(val[i], val[k]); + ++pi[n]; + } + for (j = i+1; j < n; ++j) { + if (val[j][i].val == 0) continue; + val[j][i]/= val[i][i]; + for (k = i+1; k < n; ++k) + val[j][k] -= val[j][i] * val[i][k]; + } + } + } + bool isRegular() const { return pi[n] >= 0; } + ModVector solve(ModVector b) { + vector x(b.size(), ModInt(0, mod)); + for (int i = 0; i < n; ++i) { + x[i] = b[pi[i]]; + for (int k = 0; k < i; ++k) + x[i] -= val[i][k] * x[k]; + } + for (int i = n-1; i >= 0; --i) { + for (int k = i+1; k < n; ++k) + x[i] -= val[i][k] * x[k]; + x[i] /= val[i][i]; + } + return x; + } + ModMatrix inverse() { // do not compute the inverse + ModMatrix B(n, n, mod); + for (int j = 0; j < n; ++j) { + for (int i = 0; i < n; ++i) { + if (pi[i] == j) B.val[i][j].val = 1; + for (int k = 0; k < i; k++) + B.val[i][j] -= val[i][k] * B.val[k][j]; + } + for (int i = n-1; i >= 0; --i) { + for (int k = i+1; k < n; ++k) + B.val[i][j] -= val[i][k] * B.val[k][j]; + B.val[i][j] /= val[i][i]; + } + } + return B; + } + ModInt det() { + ModInt D = val[0][0]; + for (int i = 1; i < n; i++) + D *= val[i][i]; + return ((pi[n] - n) % 2 != 0) ? -D : D; + } +}; + +void mulTest() { + Int mod = 1e9+7; + int m = 4, n = 4; + ModMatrix A(m,n,mod); + ModMatrix B(m,n,mod); + vector b(n, ModInt(0, mod)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + A(i,j).val = rand() % mod; + B(i,j).val = rand() % mod; + } + b[i].val = rand() % mod; + } + ModMatrix C = A * B; + + for (int i = 0; i < C.m; ++i) { + for (int j = 0; j < C.n; ++j) { + cout << C(i,j) << " "; + } + cout << endl; + } + cout << C.det() << endl; + + LUDecomposition LU(C); + cout << LU.det() << endl; + + // A^{-1} b = x + auto x = LU.solve(b); + cout << b << " " << (C * x) << endl; + cout << "end" << endl; +} + +void CF_QUADRATIC_EQUATIONS() { + int ncase; cin >> ncase; + for (int icase = 0; icase < ncase; ++icase) { + Int a, b, c, p; + cin >> a >> b >> c >> p; + vector ans = quadraticEquation( + ModInt(a,p), ModInt(b,p), ModInt(c,p)); + cout << ans.size(); + for (int i = 0; i < ans.size(); ++i) + cout << " " << ans[i].val; + cout << endl; + } +} + +void CF_DISCLOG() { + ModInt a(21309,999998999999), b(696969,999998999999); + cout << log(a, b) << endl; +} + +int SPOJ_MIFF() { + for (int icase = 0; ; ++icase) { + int n, p; scanf("%d %d", &n, &p); + if (n == 0 && p == 0) break; + if (icase > 0) printf("\n"); + ModMatrix A(n, n, p); + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + scanf("%d", &A(i,j)); + + ModMatrix B = A.inv(); + if (B.m > 0) { + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + printf("%d ", B(i,j)); + } + printf("\n"); + } + } else { + printf("singular\n"); + } + } +} + +int main() { + SPOJ_MIFF(); + //CF_DISCLOG(); + //CF_QUADRATIC_EQUATIONS(); + //mulTest(); +} From b0b42c6f6e986d46263cab2b0cc1fbfbc35d5512 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 28 Jan 2018 17:49:39 +0900 Subject: [PATCH 123/141] Modular Arithmetics --- math/modular_arithmetics.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/math/modular_arithmetics.cc b/math/modular_arithmetics.cc index 70d495a..93bd23f 100644 --- a/math/modular_arithmetics.cc +++ b/math/modular_arithmetics.cc @@ -121,15 +121,15 @@ ModInt sqrt(ModInt n) { ModInt t = pow(n, Q); ModInt R = pow(n, (Q+1)/2); while (t.val != 1) { - int i = 0; + int i = 0; for (ModInt s = t; s.val != 1; s *= s) ++i; if (M == i) exit(0); ModInt b = pow(c, 1<<(M-i-1)); - M = i; + M = i; c = b*b; t *= c; - R *= b; - } + R *= b; + } return R; } vector quadraticEquation(ModInt a, ModInt b, ModInt c) { From 1a0a30bef08eab71d08dc25d61766de90cd9fcd7 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 28 Jan 2018 18:29:37 +0900 Subject: [PATCH 124/141] Modular Arithmetics --- math/modular_arithmetics.cc | 40 ++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/math/modular_arithmetics.cc b/math/modular_arithmetics.cc index 93bd23f..ddd61c6 100644 --- a/math/modular_arithmetics.cc +++ b/math/modular_arithmetics.cc @@ -97,9 +97,9 @@ ModInt stringToModInt(string s, Int mod) { // compute inv[1], inv[2], ..., inv[mod-1] in O(n) time vector inverse(Int mod) { vector inv(mod, ModInt(0, mod)); - inv[1] = 1; + inv[1].val = 1; for (Int a = 2; a < mod; ++a) - inv[a] = inv[mod % a] * (mod - mod/a); + inv[a] = inv[mod % a] * ModInt(mod - mod/a,mod); return inv; } @@ -241,32 +241,26 @@ struct ModMatrix { static ModMatrix zero(int n, Int mod) { return ModMatrix(n, n, mod); } - // Gauss-Jordan-Blankinship Elimination - // It can be used for any composite modulo (Euclidean domain). + // mod should be prime ModMatrix inv() const { ModMatrix B = eye(n, mod); - vector> a = val; + vector> a = val; vector> &b = B.val; - for (int j = 0; j < n; ++j) { - // minimum nonzero をとって - // Blankinship type の吐き出しを行う - for (int i = 0; i < n; ++i) { - if (i == j) continue; - while (a[i][j].val) { - ModInt t(a[j][j].val/a[i][j].val, mod); - for (int k = j; k < n; ++k) swap(a[i][k], a[j][k]-=t*a[i][k]); - for (int k = 0; k < n; ++k) swap(b[i][k], b[j][k]-=t*b[i][k]); - } - } - if (a[j][j].val == 0) return ModMatrix(0,0,0); - } - for (int i = 0; i < n; ++i) { - for (int j = 0; j < n; ++j) { - cout << a[i][j] << " "; + for (int i = 0, j, k; i < n; ++i) { + for (j = i; j < n && a[j][i].val == 0; ++j); + if (j == n) return ModMatrix(0,0,0); // regularity is checked by m = 0 + swap(a[i], a[j]); + swap(b[i], b[j]); + ModInt inv = a[i][i].inv(); + for (k = i; k < n; ++k) a[i][k] *= inv; + for (k = 0; k < n; ++k) b[i][k] *= inv; + for (j = 0; j < n; ++j) { + if (i == j || a[j][i].val == 0) continue; + ModInt c = a[j][i]; + for (k = i; k < n; ++k) a[j][k] -= c * a[i][k]; + for (k = 0; k < n; ++k) b[j][k] -= c * b[i][k]; } - cout << endl } - return B; } // It can be used for any composite modulo. From c02cf67e073e153f0bb8df24e0ea1d501c0bbb1d Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 28 Jan 2018 22:24:11 +0900 Subject: [PATCH 125/141] Modular Arithmetics --- math/modular_arithmetics.cc | 139 ++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 79 deletions(-) diff --git a/math/modular_arithmetics.cc b/math/modular_arithmetics.cc index ddd61c6..5110efe 100644 --- a/math/modular_arithmetics.cc +++ b/math/modular_arithmetics.cc @@ -43,9 +43,10 @@ ostream &operator<<(ostream &os, const vector> &v) { } using Int = long long; struct ModInt { - Int val, mod; - ModInt(Int v, Int m) : val(v), mod(m) { } - ModInt operator-() const { return ModInt(val?mod-val:val,mod); } + static Int mod; // Set this value + Int val; + ModInt(Int v=0) : val(v%mod) { } + ModInt operator-() const { return ModInt(val?mod-val:val); } ModInt &operator+=(ModInt a) { if ((val += a.val) >= mod) val -= mod; return *this; @@ -69,37 +70,38 @@ struct ModInt { val /= t; return (*this) *= a; } - ModInt inv() const { return ModInt(1,mod) /= (*this); } + ModInt inv() const { return ModInt(1) /= (*this); } bool operator<(ModInt x) const { return val < x.val; } }; -// ModInt modInt(Int v) { return ModInt(v,MOD); } +Int ModInt::mod = 1e9+7; + ostream &operator<<(ostream &os, ModInt a) { os << a.val; return os; } ModInt operator+(ModInt a, ModInt b) { return a += b; } ModInt operator-(ModInt a, ModInt b) { return a -= b; } ModInt operator*(ModInt a, ModInt b) { return a *= b; } ModInt operator/(ModInt a, ModInt b) { return a /= b; } ModInt pow(ModInt a, Int e) { - ModInt x(1, a.mod); + ModInt x(1); for (; e > 0; e /= 2) { if (e % 2 == 1) x *= a; a *= a; } return x; } -ModInt stringToModInt(string s, Int mod) { +ModInt stringToModInt(string s) { Int val = 0; for (int i = 0; i < s.size(); ++i) - val = (val*10 + (s[i]-'0')) % mod; - return ModInt(val, mod); + val = (val*10 + (s[i]-'0')) % ModInt::mod; + return ModInt(val); } - // compute inv[1], inv[2], ..., inv[mod-1] in O(n) time -vector inverse(Int mod) { - vector inv(mod, ModInt(0, mod)); +vector inverse() { + Int mod = ModInt::mod; + vector inv(mod); inv[1].val = 1; for (Int a = 2; a < mod; ++a) - inv[a] = inv[mod % a] * ModInt(mod - mod/a,mod); + inv[a] = inv[mod % a] * ModInt(mod - mod/a); return inv; } @@ -113,9 +115,10 @@ bool isQuadraticResidue(ModInt n) { return n.val == 0 || n.mod == 2 || pow(n, (n.mod-1)/2).val == 1; } ModInt sqrt(ModInt n) { - if (n.val == 0 || n.mod == 2) return n; - int M = __builtin_ctz(n.mod-1), Q = (n.mod-1)>>M; - ModInt z(2, n.mod); + const Int mod = ModInt::mod; + if (n.val == 0 || mod == 2) return n; + int M = __builtin_ctz(mod-1), Q = (mod-1)>>M; + ModInt z(2); while (isQuadraticResidue(z)) ++z.val; ModInt c = pow(z, Q); ModInt t = pow(n, Q); @@ -133,10 +136,10 @@ ModInt sqrt(ModInt n) { return R; } vector quadraticEquation(ModInt a, ModInt b, ModInt c) { - if (a.mod == 2) { + if (ModInt::mod == 2) { vector ans; if (c.val == 0) ans.push_back(c); - if ((a + b + c).val == 0) ans.push_back(ModInt(1,2)); + if ((a + b + c).val == 0) ans.push_back(ModInt(1)); return ans; } else { b /= (a+a); c /= a; @@ -150,13 +153,11 @@ vector quadraticEquation(ModInt a, ModInt b, ModInt c) { } // Discrete Logarithm by Shanks' Baby-Step Giant-Step -// // Find k such that a^k == b -// Int log(ModInt a, ModInt b) { - Int h = ceil(sqrt(a.mod+1e-9)); + Int h = ceil(sqrt(ModInt::mod+1e-9)); unordered_map hash; - ModInt x(1, a.mod); + ModInt x(1); for (Int i = 0; i < h; ++i) { if (!hash.count(x.val)) hash[x.val] = i; x *= a; @@ -170,41 +171,14 @@ Int log(ModInt a, ModInt b) { return -1; } - -// -// find solution z.val such that -// z.val == x.val (mod x.mod), for all x. -// the solution is unique in modulo z.mod. -// -Int extgcd(Int a, Int b, Int&x, Int&y) { - for (Int u = y = 1, v = x = 0; a; ) { - Int q = b / a; - swap(x -= q * u, u); - swap(y -= q * v, v); - swap(b -= q * a, a); - } - return b; // a x + b y == gcd(a, b) -} -ModInt chineseRemainder(vector modular) { - ModInt z(0, 1); // z == 0 (mod 1) - for (ModInt x: modular) { - Int u, v, g = extgcd(x.mod, z.mod, u, v); - z.val = z.val*u*x.mod + x.val*v*z.mod; - z.mod = z.mod * (x.mod / g); - } - if ((z.val %= z.mod) < 0) z.val += z.mod; - return z; -} - struct ModMatrix { int m, n; // m times n matrix vector> val; - Int mod; ModInt &operator()(int i, int j) { return val[i][j]; } - ModMatrix(int m, int n, Int mod) : - m(m), n(n), mod(mod), val(m, vector(n, ModInt(0,mod))) { } + ModMatrix(int m, int n) : + m(m), n(n), val(m, vector(n)) { } ModMatrix operator-() const { - ModMatrix A(m, n, mod); + ModMatrix A(m, n); for (int i = 0; i < m; ++i) for (int j = 0; j < n; ++j) A.val[i][j] = -val[i][j]; @@ -224,7 +198,7 @@ struct ModMatrix { } ModMatrix &operator*=(ModMatrix A) { for (int i = 0; i < m; ++i) { - vector row(A.n, ModInt(0, A.mod)); + vector row(A.n); for (int j = 0; j < A.n; ++j) { for (int k = 0; k < A.m; ++k) row[j] += val[i][k] * A.val[k][j]; @@ -233,22 +207,22 @@ struct ModMatrix { } return *this; } - static ModMatrix eye(int n, Int mod) { - ModMatrix I(n, n, mod); + static ModMatrix eye(int n) { + ModMatrix I(n, n); for (int i = 0; i < n; ++i) I.val[i][i].val = 1; return I; } - static ModMatrix zero(int n, Int mod) { - return ModMatrix(n, n, mod); + static ModMatrix zero(int n) { + return ModMatrix(n, n); } // mod should be prime ModMatrix inv() const { - ModMatrix B = eye(n, mod); + ModMatrix B = eye(n); vector> a = val; vector> &b = B.val; for (int i = 0, j, k; i < n; ++i) { for (j = i; j < n && a[j][i].val == 0; ++j); - if (j == n) return ModMatrix(0,0,0); // regularity is checked by m = 0 + if (j == n) return ModMatrix(0,0); // regularity is checked by m = 0 swap(a[i], a[j]); swap(b[i], b[j]); ModInt inv = a[i][i].inv(); @@ -266,12 +240,12 @@ struct ModMatrix { // It can be used for any composite modulo. ModInt det() const { vector> a = val; - ModInt D(1, mod); + ModInt D(1); for (int j = 0; j < n; ++j) { for (int i = j+1; i < n; ++i) { while (a[i][j].val) { D = -D; - ModInt t(a[j][j].val/a[i][j].val, mod); + ModInt t(a[j][j].val/a[i][j].val); for (int k = j; k < n; ++k) swap(a[i][k], a[j][k] -= t * a[i][k]); } @@ -285,7 +259,7 @@ ModMatrix operator+(ModMatrix A, ModMatrix B) { return A += B; } ModMatrix operator-(ModMatrix A, ModMatrix B) { return A -= B; } ModMatrix operator*(ModMatrix A, ModMatrix B) { return A *= B; } ModMatrix pow(ModMatrix A, int k) { - ModMatrix X = ModMatrix::eye(A.n, A.mod); + ModMatrix X = ModMatrix::eye(A.n); for (; k > 0; k /= 2) { if (k % 2 == 1) X *= A; A *= A; @@ -293,7 +267,7 @@ ModMatrix pow(ModMatrix A, int k) { return X; } ModInt dot(ModMatrix A, ModMatrix B) { - ModInt val(0, A.mod); + ModInt val; for (int i = 0; i < A.m; ++i) for (int j = 0; j < A.n; ++j) val += A.val[i][j] * B.val[i][j]; @@ -301,13 +275,18 @@ ModInt dot(ModMatrix A, ModMatrix B) { } using ModVector = vector; ModVector operator*(ModMatrix A, ModVector x) { - vector y(A.m, ModInt(0, A.mod)); + vector y(A.m); for (int i = 0; i < A.m; ++i) for (int j = 0; j < A.n; ++j) y[i] += A.val[i][j] * x[j]; return y; } - +ModInt dot(ModVector a, ModVector b) { + ModInt val; + for (int i = 0; i < a.size(); ++i) + val += a[i] * b[i]; + return val; +} // // Only available for prime modulos. @@ -318,8 +297,7 @@ struct LUDecomposition { int n; vector pi; vector> val; - Int mod; - LUDecomposition(ModMatrix A) : n(A.n), val(A.val), mod(A.mod) { + LUDecomposition(ModMatrix A) : n(A.n), val(A.val) { pi.resize(n+1); iota(all(pi), 0); for (int i = 0, j, k; i < n; ++i) { @@ -341,7 +319,7 @@ struct LUDecomposition { } bool isRegular() const { return pi[n] >= 0; } ModVector solve(ModVector b) { - vector x(b.size(), ModInt(0, mod)); + vector x(b.size()); for (int i = 0; i < n; ++i) { x[i] = b[pi[i]]; for (int k = 0; k < i; ++k) @@ -355,7 +333,7 @@ struct LUDecomposition { return x; } ModMatrix inverse() { // do not compute the inverse - ModMatrix B(n, n, mod); + ModMatrix B(n, n); for (int j = 0; j < n; ++j) { for (int i = 0; i < n; ++i) { if (pi[i] == j) B.val[i][j].val = 1; @@ -379,17 +357,17 @@ struct LUDecomposition { }; void mulTest() { - Int mod = 1e9+7; + ModInt::mod = 1e9+7; int m = 4, n = 4; - ModMatrix A(m,n,mod); - ModMatrix B(m,n,mod); - vector b(n, ModInt(0, mod)); + ModMatrix A(m,n); + ModMatrix B(m,n); + vector b(n); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { - A(i,j).val = rand() % mod; - B(i,j).val = rand() % mod; + A(i,j).val = rand() % ModInt::mod; + B(i,j).val = rand() % ModInt::mod; } - b[i].val = rand() % mod; + b[i].val = rand() % ModInt::mod; } ModMatrix C = A * B; @@ -415,8 +393,9 @@ void CF_QUADRATIC_EQUATIONS() { for (int icase = 0; icase < ncase; ++icase) { Int a, b, c, p; cin >> a >> b >> c >> p; + ModInt::mod = p; vector ans = quadraticEquation( - ModInt(a,p), ModInt(b,p), ModInt(c,p)); + ModInt(a), ModInt(b), ModInt(c)); cout << ans.size(); for (int i = 0; i < ans.size(); ++i) cout << " " << ans[i].val; @@ -425,7 +404,8 @@ void CF_QUADRATIC_EQUATIONS() { } void CF_DISCLOG() { - ModInt a(21309,999998999999), b(696969,999998999999); + ModInt::mod = 999998999999; + ModInt a(21309), b(696969); cout << log(a, b) << endl; } @@ -434,7 +414,8 @@ int SPOJ_MIFF() { int n, p; scanf("%d %d", &n, &p); if (n == 0 && p == 0) break; if (icase > 0) printf("\n"); - ModMatrix A(n, n, p); + ModInt::mod = p; + ModMatrix A(n, n); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) scanf("%d", &A(i,j)); From 44755c46b0dc1b966a10357cb0ce1cd6dea10b35 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 30 Jan 2018 09:06:30 +0900 Subject: [PATCH 126/141] Delete modular_arithmetics.cc --- number_theory/modular_arithmetics.cc | 179 --------------------------- 1 file changed, 179 deletions(-) delete mode 100644 number_theory/modular_arithmetics.cc diff --git a/number_theory/modular_arithmetics.cc b/number_theory/modular_arithmetics.cc deleted file mode 100644 index 32e0ce8..0000000 --- a/number_theory/modular_arithmetics.cc +++ /dev/null @@ -1,179 +0,0 @@ -// -// Modular arithmetics (long long) -// -// Note: -// int < 2^31 < 10^9 -// long long < 2^63 < 10^18 -// -// feasible for M < 2^62 (10^18 < 2^62 < 10^19) -// -// -// Verified: -// SPOJ 11409: Fibonacci With a Twist -// SPOJ 9832: Matrix Inverse -// -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - - -#define All(c) c.begin(), c.end() -#define FOR(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();++i) -#define REP(i,n) for(int i=0;i vec; -typedef vector mat; - -ll add(ll a, ll b, ll M) { - a += b; - if (a >= M) a -= M; - return a; -} -ll sub(ll a, ll b, ll M) { - if (a < b) a += M; - return a - b; -} - -// Correctness of mul -// ab = floor(ab / M) * M + (ab % M) -// -> (ab % M) = ab - floor(ab / M) * M -ll mul(ll a, ll b, ll M) { - ll r = a*b - floor(1.0*a*b/M)*M; - return r < 0 ? r + M : r >= M ? r - M : r; -} -ll pow(ll a, ll b, ll M) { - ll x = 1; - for (; b > 0; b >>= 1) { - if (b & 1) x = mul(x, a, M); - a = mul(a, a, M); - } - return x; -} -ll div(ll a, ll b, ll M) { - ll u = 1, x = 0, s = b, t = M; - while (s) { - ll q = t / s; - swap(x -= u * q, u); - swap(t -= s * q, s); - } - if (a % t) return -1; // infeasible - return mul(x < 0 ? x + M : x, a / t, M); -} - - -// Modular Matrix -mat eye(int n) { - mat I(n, vec(n)); - REP(i, n) I[i][i] = 1; - return I; -} -mat zeros(int n) { - return mat(n, vec(n)); -} -mat mul(mat A, mat B, ll M) { - int l = A.size(), m = B.size(), n = B[0].size(); - mat C(l, vec(n)); - REP(i,l) REP(k,m) REP(j,n) - C[i][j] = add(C[i][j], mul(A[i][k], B[k][j], M), M); - return C; -} -mat pow(mat A, ll b, ll M) { - mat X = eye(A.size()); - for (; b > 0; b >>= 1) { - if (b & 1) X = mul(X, A, M); - A = mul(A, A, M); - } - return X; -} -// assume: M is prime (singular ==> -// verify: SPOJ9832 -mat inv(mat A, ll M) { - int n = A.size(); - mat B(n, vec(n)); - for (int i = 0; i < n; ++i) - B[i][i] = 1; - - for (int i = 0; i < n; ++i) { - int j = i; - while (j < n && A[j][i] == 0) ++j; - if (j == n) return {}; - swap(A[i], A[j]); - swap(B[i], B[j]); - - ll inv = div(1, A[i][i], M); - for (int k = i; k < n; ++k) - A[i][k] = mul(A[i][k], inv, M); - for (int k = 0; k < n; ++k) - B[i][k] = mul(B[i][k], inv, M); - for (int j = 0; j < n; ++j) { - if (i == j || A[j][i] == 0) continue; - ll cor = A[j][i]; - for (int k = i; k < n; ++k) - A[j][k] = sub(A[j][k], mul(cor, A[i][k], M), M); - for (int k = 0; k < n; ++k) - B[j][k] = sub(B[j][k], mul(cor, B[i][k], M), M); - } - } - return B; -} - - - -void disp(mat A) { - cout << "["; - REP(i, A.size()) { - if (i != 0) cout << " "; - REP(j, A[i].size()) { - cout << A[i][j]; - if (j != A[i].size()-1) cout << ", "; - else cout << "; "; - } - cout << endl; - } - cout << endl; -} - - -ll binomial(ll n, ll k, ll M) { - ll num = 1, den = 1; - while (n > 0 || k > 0) { - ll m = n % M, l = k % M; - if (m < l) return 0; - if (l > m - l) l = m - l; - while (l > 0) { - num = mul(num, m--, M); - den = mul(den, l--, M); - } - n /= M; k /= M; - } - return div(num, den, M); -} - - -// tick a time -double tick() { - static clock_t oldtick; - clock_t newtick = clock(); - double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; - oldtick = newtick; - return diff; -} - - -const int N = 10000000; -ll x[N]; -int main() { -} From 0fbe8aa14277247440c0e999ae563129ed5486c0 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 30 Jan 2018 09:07:01 +0900 Subject: [PATCH 127/141] Modular Arithmetics --- {math => number_theory}/modular_arithmetics.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {math => number_theory}/modular_arithmetics.cc (100%) diff --git a/math/modular_arithmetics.cc b/number_theory/modular_arithmetics.cc similarity index 100% rename from math/modular_arithmetics.cc rename to number_theory/modular_arithmetics.cc From 8b15556b2c891466a961c555232be4a8200a0678 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Fri, 2 Feb 2018 04:28:37 +0900 Subject: [PATCH 128/141] Update gabow_edmonds.cc --- graph/gabow_edmonds.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/graph/gabow_edmonds.cc b/graph/gabow_edmonds.cc index 2c245b2..a0b5445 100644 --- a/graph/gabow_edmonds.cc +++ b/graph/gabow_edmonds.cc @@ -1,4 +1,6 @@ // +// !!It may incur the index-out-of-range error!! +// // General Graph Matching (Gabow-Edmonds) // // Description: From 7036d374a32a0797a84b8efb295943caf42bbace Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sat, 3 Feb 2018 09:07:55 -0600 Subject: [PATCH 129/141] Gabow's simplified version of Edmonds' Blossom Algorithm --- graph/gabow_edmonds.cc | 252 ++++++++++++++++++++++++++--------------- 1 file changed, 161 insertions(+), 91 deletions(-) diff --git a/graph/gabow_edmonds.cc b/graph/gabow_edmonds.cc index a0b5445..455b9a4 100644 --- a/graph/gabow_edmonds.cc +++ b/graph/gabow_edmonds.cc @@ -1,127 +1,197 @@ // -// !!It may incur the index-out-of-range error!! -// // General Graph Matching (Gabow-Edmonds) // // Description: -// It computes a maximum matching in a general graph. +// +// For a graph G = (V, E), a matching M is a set of edges +// such that any vertex is contained in M at most once. +// The matching with maximum cardinality is computed by +// the Edmonds blossom algorithm. +// +// This implementation is the Gabow's simplified version +// with the lazy update technique to improve the complexity +// in sparse graphs. +// +// +// Complexity: +// +// O(n m log n) // -// Algorithm: -// Gabow's simplified version of Edmonds' blossom algorithm. -// -// Comlexity: -// O(n^3) // // Verified: -// LA3820, LA4130 +// +// SPOJ ADABLOOM +// // // References: // H.Gabow (1976): // An efficient implementation of Edmonds' algorithm for maximum matching on graphs. // Journal of the ACM, vol.23, no.2, pp.221-234. // +// http://min-25.hatenablog.com/entry/2016/11/21/222625 +// +// -#include -#include -#include -#include -#include -#include -#include -#include - +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include using namespace std; -struct graph { +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +struct Graph { int n; - vector> adj; - graph(int n) : n(n), adj(n) { }; - void add_edge(int x, int y) { - adj[x].push_back(y); - adj[y].push_back(x); + vector< vector > adj; + Graph(int n) : n(n), adj(n) { }; + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); } - queue Q; - vector label, mate, cycle; - void rematch(int x, int y) { - int m = mate[x]; mate[x] = y; - if (mate[m] == x) { - if (label[x] < n) { - rematch(mate[m] = label[x], m); + + vector mate; + int maximumMatching() { + mate.assign(n+1, n); + vector first(n+1, n), que(n); + vector> label(n+1, make_pair(-1,-1)); + int head = 0, tail = 0; + + function rematch = [&](int v, int w) { + int t = mate[v]; mate[v] = w; + if (mate[t] != v) return; + if (label[v].snd == -1) { + mate[t] = label[v].fst; + rematch(mate[t], t); } else { - int s = (label[x]-n)/n, t = (label[x]-n)%n; - rematch(s, t); rematch(t, s); + int x, y; tie(x, y) = label[v]; + rematch(x, y); rematch(y, x); } - } - } - void traverse(int x) { - vector save = mate; - rematch(x, x); - for (int u = 0; u < n; ++u) - if (mate[u] != save[u]) cycle[u] ^= 1; - save.swap(mate); - } - void relabel(int x, int y) { - cycle = vector(n, 0); - traverse(x); - traverse(y); - for (int u = 0; u < n; ++u) { - if (!cycle[u] || label[u] >= 0) continue; - label[u] = n+x+y*n; - Q.push(u); - } - } - int augment(int r) { - label.assign(n, -2); - label[r] = -1; - Q = queue(); Q.push(r); - while (!Q.empty()) { - int x = Q.front(); Q.pop(); - for (int y: adj[x]) { - if (mate[y] < 0 && r != y) { - rematch(mate[y] = x, y); return 1; - } else if (label[y] >= -1) { - relabel(x, y); - } else if (label[mate[y]] < -1) { - label[mate[y]] = x; - Q.push(mate[y]); + }; + auto relabel = [&](int x, int y) { + function findFirst = [&](int u) { + return label[first[u]].fst < 0 ? first[u] : + first[u] = findFirst(first[u]); + }; + int r = findFirst(x), s = findFirst(y); + if (r == s) return; + auto h = make_pair(~x, y); + label[r] = label[s] = h; + int join; + while (1) { + if (s != n) swap(r, s); + r = findFirst(label[mate[r]].fst); + if (label[r] == h) { + join = r; + break; + } else { + label[r] = h; } } - } - return 0; - } - int maximum_matching() { - mate.assign(n, -2); + for (int v: {first[x], first[y]}) { + for (; v != join; v = first[label[mate[v]].fst]) { + label[v] = make_pair(x, y); + first[v] = join; + que[tail++] = v; + } + } + }; + auto augment = [&](int u) { + label[u] = make_pair(n, -1); + first[u] = n; + head = tail = 0; + for (que[tail++] = u; head < tail;) { + int x = que[head++]; + for (int y: adj[x]) { + if (mate[y] == n && y != u) { + mate[y] = x; + rematch(x, y); + return true; + } else if (label[y].fst >= 0) { + relabel(x, y); + } else if (label[mate[y]].fst == -1) { + label[mate[y]].fst = x; + first[mate[y]] = y; + que[tail++] = mate[y]; + } + } + } + return false; + }; int matching = 0; - for (int u = 0; u < n; ++u) - if (mate[u] < 0) matching += augment(u); + for (int u = 0; u < n; ++u) { + if (mate[u] < n || !augment(u)) continue; + ++matching; + for (int i = 0; i < tail; ++i) + label[que[i]] = label[mate[que[i]]] = make_pair(-1,-1); + label[n] = make_pair(-1, -1); + } return matching; } }; -int doit() { - int n, m; - scanf("%d %d", &n, &m); - vector v(n); - for (int i = 0; i < n; ++i) { - scanf("%d", &v[i]); +void LA3820() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n, m; + scanf("%d %d", &n, &m); + vector v(n); + for (int i = 0; i < n; ++i) { + scanf("%d", &v[i]); + } + set S; + for (int i = 0; i < m; ++i) { + int x; + scanf("%d", &x); + S.insert(x); + } + Graph G(n); + for (int i = 0; i < n; ++i) { + for (int j = i+1; j < n; ++j) { + if (S.count(v[i] + v[j])) + G.addEdge(i, j); + } + } + printf("%d\n", G.maximumMatching()); } - set S; +} + +void UOJ79() { + int n, m; cin >> n >> m; + Graph g(n); for (int i = 0; i < m; ++i) { - int x; - scanf("%d", &x); - S.insert(x); + int u, v; + cin >> u >> v; + g.addEdge(u-1, v-1); } - - graph g(n); - for (int i = 0; i < n; ++i) { - for (int j = i+1; j < n; ++j) { - if (S.count(v[i] + v[j])) - g.add_edge(i, j); + cout << g.maximumMatching() << endl; + for (int u = 0; u < n; ++u) { + if (u > 0) cout << " "; + if (g.mate[u] >= n) cout << 0; + else cout << g.mate[u]+1; + } + cout << endl; +} +void SPOJ_ADABLOOM() { + int ncase; scanf("%d", &ncase); + for (int icase; icase < ncase; ++icase) { + int n; scanf("%d", &n); + vector a(n); + for (int i = 0; i < n; ++i) + scanf("%lld", &a[i]); + random_shuffle(all(a)); + Graph g(n); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (a[i] < (a[i] ^ a[j]) && (a[i] ^ a[j]) < a[j]) g.addEdge(i, j); + } } + cout << g.maximumMatching() << endl; } - return g.maximum_matching(); } + int main() { - doit(); + SPOJ_ADABLOOM(); + //UOJ79(); + //LA3820(); } From 400f2f633d18508288a45307d32d258188dfb38b Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 4 Feb 2018 04:23:02 +0900 Subject: [PATCH 130/141] Hopcroft-Tarjan's Articulation Point / Biconnected Components --- graph/articulation_points.cc | 147 +++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 57 deletions(-) diff --git a/graph/articulation_points.cc b/graph/articulation_points.cc index 07c5dd0..62b6638 100644 --- a/graph/articulation_points.cc +++ b/graph/articulation_points.cc @@ -1,5 +1,5 @@ // -// Articulation points / Biconnected components +// Block-Cut Tree (Articulation points / Biconnected components) // // Description: // Let G = (V, E). If G-v is disconnected, v in V is said to @@ -7,25 +7,19 @@ // it is said to be biconnected. // // A biconnected component is a maximal biconnected subgraph. -// The algorithm finds all articulation points and biconnected -// components. +// The algorithm finds all articulation points and biconnected +// components. It can be obtained by the Hopcroft-Tarjan DFS. // -// The most important fact is that by contracting biconnected -// components we obtain a tree, which is called the block tree. -// -// -// Algorithm: -// Hopcroft-Tarjan's DFS based algorithm. -// -// Single DFS finds a block tree rooted from the component -// that contains the specified root. +// We maintain the biconnected component decomposition by the +// block tree whose vertices are the blocks and the articulation +// points. By contracting the graph by the articulation points, +// we obtain the intersection graph of the blocks. // // Complexity: // O(n + m). // // Verified: -// SPOJ 14956: Submerging Island (articulation point) -// POJ 2942: Knights of the Round Table (biconnected components) +// AOJ_GRL_3_A (articulation point) // // References: // J. Hopcroft and R. E. Tarjan (1973): @@ -33,68 +27,107 @@ // Communications of the ACM, vol.16, no.6, pp.372-378. // -#include -#include -#include -#include -#include -#include +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include using namespace std; #define fst first #define snd second #define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } -struct graph { +struct Graph { int n; vector> adj; - graph(int n) : n(n), adj(n) { } - void add_edge(int src, int dst) { - adj[src].push_back(dst); - adj[dst].push_back(src); + Graph(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); } +}; - void biconnected_components() { - vector num(n), low(n), S; - unordered_set arts; +// +// bcc.n-bcc.block.size() is the number of articulation points +// index[u] is the corresponding node in the block-cut tree. +// Here, if u in block[k] then +// if u is an articulation point, k in adj[index[u]] +// otherwise, index[u] = k +// +struct BiconnectedComponents : Graph { + vector is_articulation, index; + vector> block; - function dfs = [&](int p, int u, int &t) { - num[u] = low[u] = ++t; - S.push_back(u); - for (int v: adj[u]) { - if (v == p) continue; - if (num[v] == 0) { - dfs(u, v, t); + BiconnectedComponents(Graph g) : Graph(0) { + vector low(g.n), num(g.n), cur(g.n), par(g.n, -1), path; + is_articulation.resize(g.n); + for (int s = 0; s < g.n; ++s) { + if (num[s]) continue; + int time = 0; + vector stack = {s}; + while (!stack.empty()) { + int u = stack.back(); + if (cur[u] == 0) { + low[u] = num[u] = ++time; + path.push_back(u); + } + if (cur[u] == g.adj[u].size()) { + stack.pop_back(); + } else if (cur[u] >= 0) { + int v = g.adj[u][cur[u]++]; + if (num[v] == 0) { + cur[u] = ~cur[u]; + stack.push_back(v); + } else if (v != par[u]) { + low[u] = min(low[u], num[v]); + } + } else { + cur[u] = ~cur[u]; + int v = g.adj[u][cur[u]-1]; low[u] = min(low[u], low[v]); if (num[u] <= low[v]) { - if (num[u] != 1 || num[v] > 2) { - // here, u is an articulation point if - // (a). u is non-root - // (b). u is root with two more children - } - vector C = {u}; // biconnected component - while (C.back() != v) { - C.push_back(S.back()); - S.pop_back(); + is_articulation[u] = (num[u] > 1 || num[v] > 2); + block.push_back({u}); + while (block.back().back() != v) { + block.back().push_back(path.back()); + path.pop_back(); } } - } else low[u] = min(low[u], num[v]); + } } - }; - for (int u = 0, t; u < n; ++u) - if (!num[u]) dfs(-1, u, t = 0); - cout << arts.size() << endl; + } + index.resize(g.n); // make a block tree + n = block.size(); + for (int u = 0; u < g.n; ++u) + if (is_articulation[u]) index[u] = n++; + adj.resize(n); + for (int k = 0; k < block.size(); ++k) { + for (int u: block[k]) { + if (!is_articulation[u]) index[u] = k; + else addEdge(k, index[u]); + } + } } }; -int main() { - for (int n, m; ~scanf("%d %d", &n, &m) && n; ) { - graph g(n); - for (int i = 0; i < m; ++i) { - int u, v; scanf("%d %d", &u, &v); - g.add_edge(u-1, v-1); - } - g.biconnected_components(); +void AOJ_GRL_3_A() { + int n, m; + scanf("%d %d", &n, &m); + Graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; scanf("%d %d", &u, &v); + g.addEdge(u, v); } + BiconnectedComponents bcc(g); + for (int u = 0; u < g.n; ++u) + if (bcc.is_articulation[u]) cout << u << endl; } + +int main() { + AOJ_GRL_3_A(); + //SPOJ_SUBMERGE(); + //test(); + /* + */ +} + From 8b1daaa3e80e5d954aac2632ef2299b1b86c55ed Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 5 Feb 2018 14:36:02 -0600 Subject: [PATCH 131/141] Kahn's topological sort --- graph/topological_sort.cc | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 graph/topological_sort.cc diff --git a/graph/topological_sort.cc b/graph/topological_sort.cc new file mode 100644 index 0000000..66cfd16 --- /dev/null +++ b/graph/topological_sort.cc @@ -0,0 +1,81 @@ +// +// Topological Sort +// +// +// Description: +// +// Let G = (V, E) be a graph. An ordering ord: [n] -> V is a topological +// ordering if i > j then there is no edge from ord[i] to ord[j]. +// G has a topological ordering if and only if G is DAG. +// +// A topological order can be obtained in O(n + m) time by using +// an iterative method (Kahn's algorithm) or a recursive method +// (by Tarjan's algorithm). The following implementation is a +// Kahn's algorithm. +// +// Note that if you want to find the all topological orders, +// +// +// Complexity: +// +// O(n + m) +// +// +// Verified: +// +// AOJ GPL_4_B +// +// References: +// +// Arthur B. Kahn (1962): +// "Topological sorting of large networks". +// Communications of the ACM, 5 (11): 558--562. +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +struct Graph { + int n; + vector> adj; + Graph(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + } +}; + +// return empty list if g has no topological order +vector topologicalSort(Graph g) { + vector deg(g.n); + for (int u = 0; u < g.n; ++u) + for (int v: g.adj[u]) ++deg[v]; + vector stack; + for (int u = 0; u < g.n; ++u) + if (!deg[u]) stack.push_back(u); + + vector order; + while (!stack.empty()) { + int u = stack.back(); stack.pop_back(); + order.push_back(u); + for (int v: g.adj[u]) + if (!--deg[v]) stack.push_back(v); + } + return order.size() == g.n ? order : vector(); +} + +int main() { + int n, m; cin >> n >> m; + Graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; cin >> u >> v; + g.addEdge(u, v); + } + auto ord = topologicalSort(g); + for (int i = 0; i < ord.size(); ++i) { + if (i > 0) cout << " "; + cout << ord[i]; + } +} From bf3828854ed0c249deb4f494ec1daf865dd1e41d Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 6 Feb 2018 09:23:53 -0600 Subject: [PATCH 132/141] Bridge-Block Tree (Bridge / Two-edge connected components) --- graph/bridge.cc | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 graph/bridge.cc diff --git a/graph/bridge.cc b/graph/bridge.cc new file mode 100644 index 0000000..de6cdba --- /dev/null +++ b/graph/bridge.cc @@ -0,0 +1,149 @@ +// +// Bridge-Block Tree (Bridge / Two-edge connected component) +// +// Description: +// Let G = (V, E). e in E is said to be a cut edge if G-e is +// disconnected If G has no cut edges, it is said to be two-edge +// connected. +// A two-edge connected component is a maximal two-edge connected +// subgraph. The algorithm finds all bridges with the two-edge +// connected components. +// +// We maintain the two-edge connected component decomposition by +// a bridge-block tree whose nodes are the two-edge connected +// components. +// +// +// Complexity: +// O(n + m). +// +// Verified: +// +// References: +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +struct Graph { + int n; + vector> adj; + Graph(int n) : n(n), adj(n) { } + void addEdge(int src, int dst) { + adj[src].push_back(dst); + adj[dst].push_back(src); + } +}; + +struct BridgeBlockTree : Graph { + vector index; // index[u] is the block index containing u + vector> block; // u in block[k] <=> index[u] == k + + BridgeBlockTree(Graph g) : Graph(0) { + index.assign(g.n, -1); + vector num(g.n), par(g.n,-1), cur(g.n); + + for (int s = 0; s < g.n; ++s) { + if (num[s]) continue; + int time = 0; + vector snum, path, stack = {s}; + while (!stack.empty()) { + int u = stack.back(); + if (cur[u] == 0) { + num[u] = ++time; + path.push_back(u); + snum.push_back(num[u]); + } + if (cur[u] == g.adj[u].size()) { + if (num[u] == snum.back()) { + snum.pop_back(); + block.push_back({}); + while (1) { + int w = path.back(); path.pop_back(); + block.back().push_back(w); + index[w] = block.size()-1; + if (u == w) break; + } + } + stack.pop_back(); + } else { + int v = g.adj[u][cur[u]++]; + if (!num[v]) { + par[v] = u; + stack.push_back(v); + } else if (v != par[u] && index[v] < 0) { + while (snum.back() > num[v]) snum.pop_back(); + } + } + } + } + n = block.size(); + adj.resize(n); + for (int u = 0; u < g.n; ++u) + if (par[u] >= 0 && index[u] != index[par[u]]) + addEdge(index[u], index[par[u]]); + } +}; + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +int main() { + Graph g(6); + g.addEdge(0, 1); + g.addEdge(1, 2); + g.addEdge(2, 0); + g.addEdge(2, 3); + g.addEdge(3, 4); + g.addEdge(4, 5); + g.addEdge(5, 3); + BridgeBlockTree t(g); + + cout << t.n << endl; + for (int u = 0; u < t.n; ++u) { + for (int v: t.adj[u]) { + cout << u << " " << v << endl; + } + } + + for (auto B: t.block) { + for (int u: B) { + cout << u << " "; + } + cout << endl; + } + for (int u = 0; u < 6; ++u) { + cout << t.index[u] << " "; + } + cout << endl; + + //g.bridgeless_component(); + /* + for (int n, m; ~scanf("%d %d", &n, &m) && n; ) { + graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; scanf("%d %d", &u, &v); + g.add_edge(u-1, v-1); + } + g.biconnected_components(); + } + */ +} From 40b1a4821e4bb1ebd49c4b5d53e3de719d8f55ea Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 6 Feb 2018 11:29:47 -0600 Subject: [PATCH 133/141] Number of lattice points below a line --- math/lattice_below_line.cc | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 math/lattice_below_line.cc diff --git a/math/lattice_below_line.cc b/math/lattice_below_line.cc new file mode 100644 index 0000000..893859f --- /dev/null +++ b/math/lattice_below_line.cc @@ -0,0 +1,71 @@ +// +// Number of lattice points below a line +// +// Description: +// +// Let a, b, n, m be nonnegative integers. The task is to compute +// sum_{i in [0,n)} floor((a + ib)/m). +// +// We compute this quantity in x-axis and y-axis alternately. +// First, let +// a = (a/m) m + (a%m), +// b = (b/m) m + (b%m). +// Then the quantity is +// sum [(a/m)+i*(b/m)] + floor(((a%m) + i(b%m))/m) +// Here, the first term is analytically evaluated. +// If b%m == 0 then the second term is zero. +// Otherwise, the task is reduced to compute +// sum_{i in [0,n)} floor((a + ib)/m) +// where a < m, b < m. By changing the axes, we can observe +// that this quantity is equal to +// sum_{i in [0,n')} floor((a' + ib')/m') +// where +// n' = (a + b n) / m, +// a' = (a + b n) % m, +// b' = m, +// m' = b. +// +// We can observe that the computation on b and m is the same +// as the computation of gcd(b,m). Thus the number of iterations +// is at most O(log m). +// +// Complexity: +// +// O(log m). + +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define aInt(c) ((c).begin()), ((c).end()) + +// +// sum_{0<=i= 0, a >= 0, b >= 0 +// +// +using Int = long long; +Int latticeBelowLine(Int n, Int a, Int b, Int m) { + Int ans = 0; + while (m) { + ans += (n-1)*n/2*(b/m) + n*(a/m); + a %= m; + b %= m; + auto z = (a+b*n); + a = z%m; + n = z/m; + swap(b, m); + } + return ans; +} + +int main() { + srand(time(0)); + Int a = rand(), b = rand(), n = rand(), m = rand(); + cout << latticeBelowLine(n, a, b, m) << endl; +} From 53b8fe26c74d6b9b6456c96759ff9bc785d32813 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Tue, 6 Feb 2018 11:41:59 -0600 Subject: [PATCH 134/141] Number of lattice points below a line --- math/lattice_below_line.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/math/lattice_below_line.cc b/math/lattice_below_line.cc index 893859f..e9ee769 100644 --- a/math/lattice_below_line.cc +++ b/math/lattice_below_line.cc @@ -6,18 +6,17 @@ // Let a, b, n, m be nonnegative integers. The task is to compute // sum_{i in [0,n)} floor((a + ib)/m). // -// We compute this quantity in x-axis and y-axis alternately. +// We compute this quantity in two directions alternately. // First, let // a = (a/m) m + (a%m), // b = (b/m) m + (b%m). // Then the quantity is // sum [(a/m)+i*(b/m)] + floor(((a%m) + i(b%m))/m) // Here, the first term is analytically evaluated. -// If b%m == 0 then the second term is zero. -// Otherwise, the task is reduced to compute +// The second term is zero if b%m == 0. Otherwise, the task is +// reduced to compute // sum_{i in [0,n)} floor((a + ib)/m) -// where a < m, b < m. By changing the axes, we can observe -// that this quantity is equal to +// where a < m, b < m. By changing the axes, this quantity is // sum_{i in [0,n')} floor((a' + ib')/m') // where // n' = (a + b n) / m, @@ -25,13 +24,17 @@ // b' = m, // m' = b. // -// We can observe that the computation on b and m is the same -// as the computation of gcd(b,m). Thus the number of iterations -// is at most O(log m). +// We evaluate the number of iterations. Since the computation +// between b and m is the same as the one of the Euclidean +// algorithm. Thus it terminates in O(log m) time. // // Complexity: // // O(log m). +// +// Verified: +// +// Somewhere #include #include @@ -43,7 +46,7 @@ using namespace std; #define fst first #define snd second -#define aInt(c) ((c).begin()), ((c).end()) +#define all(c) ((c).begin()), ((c).end()) // // sum_{0<=i= 0, a >= 0, b >= 0 From d3415627fd1ccd7a2f946fcc6ad9c546188617fd Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 7 Feb 2018 00:48:02 -0600 Subject: [PATCH 135/141] Leftist heap --- data_structure/leftist_heap.cc | 84 ++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 data_structure/leftist_heap.cc diff --git a/data_structure/leftist_heap.cc b/data_structure/leftist_heap.cc new file mode 100644 index 0000000..62e3609 --- /dev/null +++ b/data_structure/leftist_heap.cc @@ -0,0 +1,84 @@ +// +// Leftist Heap +// +// Description: +// +// Leftist heap is a heap data structure that allows +// the meld (merge) operation in O(log n) time. +// Use this for persistent heaps. +// +// Complexity: +// +// O(1) for top, O(log n) for push/pop/meld +// +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +struct LeftistHeap { + struct Node { + T key; + Node *left = 0, *right = 0; + int dist = 0; + } *root = 0; + static Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (x->key > y->key) swap(x, y); + x->right = merge(x->right, y); + if (!x->left || x->left->dist < x->dist) swap(x->left, x->right); + x->dist = (x->right ? x->right->dist : 0) + 1; + return x; + } + void push(T key) { root = merge(root, new Node({key})); } + void pop() { root = merge(root->left, root->right); } + T top() { return root->key; } +}; + +// +// Persistent Implementaiton. (allow copy) +// +template +struct PersistentLeftistHeap { + struct Node { + T key; + Node *left = 0, *right = 0; + int dist = 0; + } *root = 0; + static Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (x->key > y->key) swap(x, y); + x = new Node(*x); + x->right = merge(x->right, y); + if (!x->left || x->left->dist < x->dist) swap(x->left, x->right); + x->dist = (x->right ? x->right->dist : 0) + 1; + return x; + } + void push(T key) { root = merge(root, new Node({key})); } + void pop() { root = merge(root->left, root->right); } + T top() { return root->key; } +}; + +int main() { + PersistentLeftistHeap heap; + heap.push(3); + heap.push(1); + heap.push(4); + heap.push(1); + heap.push(5); + cout << heap.top() << endl; heap.pop(); + cout << heap.top() << endl; heap.pop(); + auto temp = heap; + cout << heap.top() << endl; heap.pop(); + cout << heap.top() << endl; heap.pop(); + cout << temp.top() << endl; temp.pop(); + cout << temp.top() << endl; temp.pop(); +} From 516f777c2431af75e50e1dae36d0e8bfced3ba6d Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Sun, 11 Feb 2018 13:46:24 +0900 Subject: [PATCH 136/141] Fisher, Kasteleyn, and Temperley algorithm for counting perfect matchings in plane graph --- graph/plane_perfect_matchings.cc | 196 +++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 graph/plane_perfect_matchings.cc diff --git a/graph/plane_perfect_matchings.cc b/graph/plane_perfect_matchings.cc new file mode 100644 index 0000000..095d48a --- /dev/null +++ b/graph/plane_perfect_matchings.cc @@ -0,0 +1,196 @@ +// +// Counting Perfect Matchings in Plane Graph +// (Fisher, Kasteleyn, and Temperley) +// +// Description: +// +// Pfaffian Orientation; see https://en.wikipedia.org/wiki/FKT_algorithm +// +// Complexity: +// +// O(n^3). +// +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Real = long double; +struct Point { + Real x, y; +}; + +struct PlaneGraph { + vector incident_edge; // vertex record + vector origin, twin, prev, next, incident_face; // edge record + vector component; // face record + int edges() const { return origin.size(); } + int vertices() const { return incident_edge.size(); } + int faces() const { return component.size(); } + + vector point; + int newVertex(Point p, int e = -1) { + point.push_back(p); + incident_edge.push_back(e); + return vertices()-1; + } + int newEdge(int o = -1) { + origin.push_back(o); + twin.push_back(-1); + prev.push_back(-1); + next.push_back(-1); + incident_face.push_back(-1); + return edges()-1; + } + int newFace(int e = -1) { + component.push_back(e); + return component.size()-1; + } + void completeFaces() { + component.clear(); + fill(all(incident_face), -1); + for (int e = 0; e < edges(); ++e) { + if (incident_face[e] >= 0) continue; + int f = newFace(e), x = e; + do { + incident_face[x] = f; + x = next[x]; + } while (x != e); + } + } + + // assume connected + vector pfaffianOrientation() { + // take any spanning tree T + vector dir(edges(), -2), seen(vertices()); + function dfs1 = [&](int u) { + seen[u] = 1; + int e = incident_edge[u]; + do { + int v = origin[twin[e]]; + if (!seen[v]) { + dir[e] = 1; + dir[twin[e]] = -dir[e]; + dfs1(v); + } + e = next[twin[e]]; + } while (e != incident_edge[u]); + }; + for (int u = 0; u < vertices(); ++u) + if (!seen[u]) dfs1(u); + + // take any dual spanning tree that does not cross T + seen = vector(faces()); + vector come(faces(), -1); + function dfs2 = [&](int f, int p) { + int parity = 0; + int free_edge = -1; + seen[f] = 1; + int e = component[f]; + do { + int g = incident_face[twin[e]]; + if (dir[e] == -2 && !seen[g]) dfs2(g, twin[e]); + if (dir[e] == -2) { assert(free_edge == -1); free_edge = e; } + else if (dir[e] == 1) ++parity; + e = next[e]; + } while (e != component[f]); + if (free_edge != -1) { + dir[free_edge] = -(parity % 2 == 0 ? -1 : +1); + dir[twin[free_edge]] = -dir[free_edge]; + } + }; + dfs2(0, -1); + return dir; + } + using Int = __int128_t; + Int countPerfectMatching() { + vector dir = pfaffianOrientation(); + int n = vertices(); + vector> A(n, vector(n)); + for (int e = 0; e < edges(); ++e) + A[origin[e]][origin[twin[e]]] = dir[e]; + + // compute determinant + Int det = 1; + for (int j = 0; j < n; ++j) { + for (int i = j+1; i < n; ++i) { + while (A[i][j]) { + det = -det; + Int t = A[j][j] / A[i][j]; + for (int k = j; k < n; ++k) + swap(A[i][k], A[j][k] -= t * A[i][k]); + } + } + det *= A[j][j]; // % mod + } + return sqrt(det + 0.1); + } +}; + +using Int = long long; +Int dominoCount(vector> table) { + int m = table.size(), n = table[0].size(); + vector> index(m, vector(n, -1)); + PlaneGraph g; + unordered_map> adj; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (table[i][j] == '.') { + index[i][j] = g.newVertex(Point({i,j})); + } + } + } + unordered_map next_inc, prev_inc; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + vector inc; + int x = index[i][j]; + int dx[] = {1,0,-1,0}, dy[] = {0,1,0,-1}; + for (int p = 0; p < 4; ++p) { + int k = i+dx[p], l = j+dy[p]; + if (k < 0 || l < 0) continue; + if (k >= table.size() || l >= table[k].size()) continue; + if (table[i][j] != '.' || table[k][l] != '.') continue; + int y = index[k][l]; + if (!adj[x].count(y)) adj[x][y] = g.newEdge(x); + if (!adj[y].count(x)) adj[y][x] = g.newEdge(y); + g.twin[adj[x][y]] = adj[y][x]; + g.twin[adj[y][x]] = adj[x][y]; + g.incident_edge[x] = adj[x][y]; + g.incident_edge[y] = adj[y][x]; + inc.push_back(adj[x][y]); + } + for (int i = 0; i < inc.size(); ++i) { + int j = (i == inc.size()-1 ? 0 : i+1); + next_inc[inc[i]] = inc[j]; + prev_inc[inc[j]] = inc[i]; + } + } + } + for (int e = 0; e < g.edges(); ++e) { + g.next[e] = prev_inc[g.twin[e]]; + g.prev[e] = g.twin[next_inc[e]]; + } + g.completeFaces(); + return g.countPerfectMatching(); +} + +void SPOJ_GNY07H() { + int ncase; + cin >> ncase; + for (int icase = 0; icase < ncase; ++icase) { + int w; + cin >> w; + vector> table(4, vector(w, '.')) ; + cout << icase+1 << " " << dominoCount(table) << endl; + } +} + +int main() { + SPOJ_GNY07H(); +} From 02236d75dc048a421a22fdf2b12ad71e26ca4180 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 12 Feb 2018 15:04:37 +0900 Subject: [PATCH 137/141] Eppstein's k shortest walks --- graph/k_shortest_walks.cc | 181 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 graph/k_shortest_walks.cc diff --git a/graph/k_shortest_walks.cc b/graph/k_shortest_walks.cc new file mode 100644 index 0000000..d37c038 --- /dev/null +++ b/graph/k_shortest_walks.cc @@ -0,0 +1,181 @@ +// +// K Shortest Walks (Simplified Eppstein) +// +// Description +// +// We are given a weighted graph. The k-shortest walks problem +// seeks k different s-t walks (paths allowing repeated vertices) +// in the increasing order of the lengths. +// +// If we maintain each walks explicitly, it must costs O(k^2 m) time. +// To avoid this complexity, we maintain the walks in a compact format. +// Let us fix a reverse shortest path tree from t. A deviation is an +// edge that is not on the tree. Any walk is represented by a concatenation +// of deviations and paths on the tree. We enumerate all possible +// deviations and use the best-first search to find the k-th solution. +// +// The Eppstein's algorithm maintains the set of deviations by +// the augmented persistent heaps and emurates the best-first search. +// Here, we implemented a simplified version of the Eppstein's algorithm, +// which uses the simple persistent heaps instead of the augmented ones. +// It increases the space from O(m + n log n) to O(m log n). +// +// Complexity: +// +// O(m log m) construction +// O(k log k) for k-th search +// +// Verified: +// +// UTPC2013_10 J K-th Cycle +// +// References: +// +// David Eppstein (1998): +// "Finding the k shortest paths", +// SIAM Journal on computing, vol.28, no.2, pp.652--673. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Graph { + int n, m = 0; + vector head; // Vertex + vector src, dst, next, prev; // Edge + + using Weight = long long; + vector weight; + Graph(int n) : n(n), head(n, -1) { } + int addEdge(int u, int v, Weight w) { + next.push_back(head[u]); + src.push_back(u); + dst.push_back(v); + weight.push_back(w); + return head[u] = m++; + } +}; +constexpr Graph::Weight INF = 1e15; + +struct KShortestWalks { + Graph g; + vector dist; + vector tree, order; + void reverseDijkstra(int t) { + vector> adj(g.n); + for (int u = 0; u < g.n; ++u) + for (int e = g.head[u]; e >= 0; e = g.next[e]) + adj[g.dst[e]].push_back(e); + dist.assign(g.n, INF); + tree.assign(g.n, ~g.m); + using Node = tuple; + priority_queue, greater> que; + que.push(make_tuple(0, t)); + dist[t] = 0; + while (!que.empty()) { + int u = get<1>(que.top()); que.pop(); + if (tree[u] >= 0) continue; + tree[u] = ~tree[u]; + order.push_back(u); + for (int e: adj[u]) { + int v = g.src[e]; + if (dist[v] > dist[u] + g.weight[e]) { + tree[v] = ~e; + dist[v] = dist[u] + g.weight[e]; + que.push(Node(dist[v], v)); + } + } + } + } + struct Node { // Persistent Heap (Leftist Heap) + int e; + Graph::Weight delta; + Node *left = 0, *right = 0; + int rnk = 0; + } *root = 0; + static Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (x->delta > y->delta) swap(x, y); + x = new Node(*x); + x->right = merge(x->right, y); + if (!x->left || x->left->rnk < x->rnk) swap(x->left, x->right); + x->rnk = (x->right ? x->right->rnk : 0) + 1; + return x; + } + vector deviation; + void buildHeap() { + deviation.resize(g.n); + for (int u: order) { + int v = -1; + for (int e = g.head[u]; e >= 0; e = g.next[e]) { + if (tree[u] == e) v = g.dst[e]; + else if (dist[g.dst[e]] < INF) { + auto delta = g.weight[e] - dist[g.src[e]] + dist[g.dst[e]]; + deviation[u] = merge(deviation[u], new Node({e, delta})); + } + } + if (v >= 0) deviation[u] = merge(deviation[u], deviation[v]); + } + } + KShortestPaths(Graph g_, int t) : g(g_) { + reverseDijkstra(t); + buildHeap(); + } + void enumerate(int s, int kth) { + int k = 0; + Node *x = deviation[s]; + Graph::Weight len = dist[s]; + ++k; + using SearchNode = tuple; + auto comp = [](SearchNode x, SearchNode y) { return get<1>(x) > get<1>(y); }; + priority_queue, decltype(comp)> que(comp); + if (x) que.push(SearchNode(x, len + x->delta)); + while (!que.empty() && k < kth) { + tie(x, len) = que.top(); que.pop(); + int e = x->e, u = g.src[e], v = g.dst[e]; + cout << len << endl; ++k; + if (deviation[v]) que.push(SearchNode(deviation[v], len+deviation[v]->delta)); + for (Node *y: {x->left, x->right}) + if (y) que.push(SearchNode(y, len + y->delta-x->delta)); + } + while (k < kth) { cout << -1 << endl; ++k; } + } +}; + +void KSH_test() { + int n = 4; + Graph g(n); + g.addEdge(0, 1, 2); + g.addEdge(0, 2, 2); + g.addEdge(1, 3, 4); + g.addEdge(2, 3, 2); + g.addEdge(1, 2, 1); + g.addEdge(2, 1, 1); + KShortestPaths ksh(g, 3); + ksh.enumerate(0, 10); +} + +void UTPC2013_10() { + int n, m, k; + scanf("%d %d %d", &n, &m, &k); + Graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; + long long w; + scanf("%d %d %lld", &u, &v, &w); + g.addEdge(u, v, w); + } + KShortestPaths ksh(g, 0); + ksh.enumerate(0, k+1); +} + +int main() { + UTPC2013_10(); + //KSH_test(); +} From 4f3455f573b3f34cfe02c960dede352b12a08ba8 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Wed, 21 Mar 2018 10:03:58 +0900 Subject: [PATCH 138/141] Disjoint Sparse Table --- data_structure/disjoint_sparse_table.cc | 78 +++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 data_structure/disjoint_sparse_table.cc diff --git a/data_structure/disjoint_sparse_table.cc b/data_structure/disjoint_sparse_table.cc new file mode 100644 index 0000000..87dced4 --- /dev/null +++ b/data_structure/disjoint_sparse_table.cc @@ -0,0 +1,78 @@ +// +// Disjoint Sparse Table +// +// Description: +// +// Let `otimes` be a binary associative operator. +// The disjoint sparse table is a data structure for a +// sequence xs that admits a query +// prod(i,j) = xs[i] `otimes` ... `otimes` xs[j-1] +// in time O(1). +// +// The structure is a segment tree whose node maintains +// prod(i,m) and prod(m,j) for all i, j in the segment. +// Then prod(i,j) is evaluated by finding the node that +// splits [i,j) and returning prod(i,m)*prod(m,j). +// +// Complexity: +// +// preprocessing O(n log n) +// query O(1) +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +struct DisjointSparseTable { + vector> ys; + Op otimes; + DisjointSparseTable(vector xs, Op otimes_) : otimes(otimes_) { + int n = 1; + while (n <= xs.size()) n *= 2; + xs.resize(n); + ys.push_back(xs); + for (int h = 1; ; ++h) { + int range = (2 << h), half = (range /= 2); + if (range > n) break; + ys.push_back(xs); + for (int i = half; i < n; i += range) { + for (int j = i-2; j >= i-half; --j) + ys[h][j] = otimes(ys[h][j], ys[h][j+1]); + for (int j = i+1; j < min(n, i+half); ++j) + ys[h][j] = otimes(ys[h][j-1], ys[h][j]); + } + } + } + T prod(int i, int j) { // [i, j) query + --j; + int h = sizeof(int)*__CHAR_BIT__-1-__builtin_clz(i ^ j); + return otimes(ys[h][i], ys[h][j]); + } +}; +template +auto makeDisjointSparseTable(vector xs, Op op) { + return DisjointSparseTable(xs, op); +} + +int main() { + vector xs = {3,1,4,1,5,1}; + int n = xs.size(); + auto otimes = [](int a, int b) { return max(a, b); }; + auto dst = makeDisjointSparseTable(xs, otimes); + + for (int i = 0; i < n; ++i) { + for (int j = i+1; j <= n; ++j) { + cout << i << " " << j << " " << dst.prod(i, j) << " "; + int a = xs[i]; + for (int k = i+1; k < j; ++k) + a = otimes(a, xs[k]); + cout << a << endl; + } + } +} From 9cca6b826f19ed7e42dd326a4fbbb9f4d34f04d3 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 7 Jun 2018 03:36:21 +0900 Subject: [PATCH 139/141] Segment Recognizer (evaluate automaton run in O(|M|) time) --- data_structure/segment_recognizer.cc | 149 +++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 data_structure/segment_recognizer.cc diff --git a/data_structure/segment_recognizer.cc b/data_structure/segment_recognizer.cc new file mode 100644 index 0000000..6e87b4b --- /dev/null +++ b/data_structure/segment_recognizer.cc @@ -0,0 +1,149 @@ +// +// Segment Recognizer +// +// Description: +// Let M be an automaton and x be a sequence of alphabets. +// The segment recognizer computes the transitioned state +// starting from s and reading x[i,j) in O(|M|) time. +// The preprocessing requires O(|M| |x|) time and space. +// +// The same method is implemented by the segment tree, +// where the time complexity is O(log n) and the space +// complexity is O(n log n). Thus, the segment recognizer +// is efficient if |M| is small. +// +// Algorithm: +// Basically, it stores all the runs from all initial +// position i and initial state s. To reduce the space, +// it merges two runs if they yields the same state. +// +// Reference +// Mikola Bojanczyk (2009): "Factorization forests", +// International Conference on Developments in Language Theory, +// pp. 1--17. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +template +struct ModuloAutomaton { + const int init = 0; + int size() const { return MOD; } + int next(int s, int d) const { return (s+d)%MOD; } + int accept(int s) const { return s==0; } +}; + +// 0: free +// 1: selected +// 2: bottom +struct IndependenceAutomaton { + const int init = 0; + int size() const { return 3; } + int next(int s, int d) const { + if (s == 0) return d; + if (s == 1) return 2*d; + if (s == 2) return s; + } + int accept(int s) const { return s!=2; } +}; + +template +struct SegmentRecognizer { + Automaton M; + vector x; + + struct Tape { + int begin; + vector sequence; + }; + vector> index; + vector tapes; + + SegmentRecognizer(Automaton M, vector x) : M(M), x(x) { + index.assign(x.size()+1, vector(M.size())); + vector stripe; + for (int r = 0; r < M.size(); ++r) { + stripe.push_back(r); + index[0][r] = stripe[r]; + tapes.push_back({0, {r}}); + } + for (int i = 0; i < x.size(); ++i) { + unordered_set available; + for (int s = 0; s < M.size(); ++s) + available.insert(s); + vector reallocate; + for (int r = 0; r < M.size(); ++r) { + int next = M.next(tapes[stripe[r]].sequence.back(), x[i]); + if (available.count(next)) { + available.erase(next); + index[i+1][next] = stripe[r]; + tapes[stripe[r]].sequence.push_back(next); + } else { + reallocate.push_back(r); + } + } + for (int r: reallocate) { + int s = *available.begin(); + stripe[r] = tapes.size(); + index[i+1][s] = stripe[r]; + tapes.push_back({i+1, {s}}); + available.erase(s); + } + } + } + + int getState(int i, int s, int j) { + while (1) { + auto &tape = tapes[index[i][s]]; + if (j - tape.begin < tape.sequence.size()) { + return tape.sequence[j - tape.begin]; + } else { + i = tape.begin + tape.sequence.size(); + s = M.next(tape.sequence.back(), x[i-1]); + } + } + } +}; +template +SegmentRecognizer makeSegmentRecognizer(Automaton M, vector s) { + return SegmentRecognizer(M, s); +} + +int main() { + IndependenceAutomaton M; + + for (int n = 2; n < (1<<24); n*=2) { + vector x(n); + for (int i = 0; i < n; ++i) { + x[i] = (rand() % 10 == 0); + } + auto recognizer = makeSegmentRecognizer(M, x); + + tick(); + int count = 0; + for (int iter = 0; iter < n; ++iter) { + int v = (rand() % n) + 1; + int u = rand() % v; + count += recognizer.getState(u, 0, v); + } + double t = tick(); + cout << n << " " << t / n << endl; + } +} From 3a44bc12aa076c73a03184ef45e0cfb974e40161 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Thu, 9 Aug 2018 18:25:29 +0900 Subject: [PATCH 140/141] Create roc-auc.cc --- machine_learning/roc-auc.cc | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 machine_learning/roc-auc.cc diff --git a/machine_learning/roc-auc.cc b/machine_learning/roc-auc.cc new file mode 100644 index 0000000..5af7947 --- /dev/null +++ b/machine_learning/roc-auc.cc @@ -0,0 +1,40 @@ +#include + +using namespace std; + +double trapezoid(double x1, double x2, double y1, double y2) { + return (y2+y1)/2 * abs(x2-x1); +} + +double auc(vector test, vector pred) { + int n = test.size(); + assert(n == pred.size()); + + vector idx(n); + for (int i = 0; i < n; ++i) idx[i] = i; + sort(idx.begin(), idx.end(), [&](int i, int j) { return pred[i] > pred[j]; }); + + double a = 0.0; + double fp = 0, tp = 0, fp_prev = 0, tp_prev = 0; + double prev_score = -1.0/0.0; + for (int i: idx) { + if (pred[i] != prev_score) { + a += trapezoid(fp, fp_prev, tp, tp_prev); + prev_score = pred[i]; + fp_prev = fp; + tp_prev = tp; + } + if (test[i] == 1) { + tp += 1; + } else { + fp += 1; + } + } + a += trapezoid(fp, fp_prev, tp, tp_prev); + return a / (tp * fp); +} +int main() { + vector test = {0, 1, 0, 1, 1}; + vector pred = {0.2, 0.3, 0.4, 0.5, 0.6}; + cout << auc(test, pred) << endl; +} From 4fdac8202e26def25c1baf9127aaaed6a2c9f7c7 Mon Sep 17 00:00:00 2001 From: Takanori MAEHARA Date: Mon, 7 Jan 2019 09:03:05 +0900 Subject: [PATCH 141/141] debug incorrect implementation of undoable union find. (path compression cannot be undo) --- data_structure/union_find_undo.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/data_structure/union_find_undo.cc b/data_structure/union_find_undo.cc index 4aff857..208ff82 100644 --- a/data_structure/union_find_undo.cc +++ b/data_structure/union_find_undo.cc @@ -27,25 +27,29 @@ struct UndoableUnionFind { UndoableUnionFind(int n) : parent(n, -1) { }; bool unite(int u, int v) { u = root(u); v = root(v); - if (u == v) return false; - if (parent[u] > parent[v]) swap(u, v); - history.push_back(make_tuple(u, v, parent[v])); - parent[u] += parent[v]; parent[v] = u; - return true; + if (u == v) { + history.push_back(make_tuple(-1,-1,-1)); + return false; + } else { + if (parent[u] > parent[v]) swap(u, v); + history.push_back(make_tuple(u, v, parent[v])); + parent[u] += parent[v]; parent[v] = u; + return true; + } } void undo() { int u, v, w; tie(u, v, w) = history.back(); history.pop_back(); + if (u == -1) return; parent[v] = w; parent[u] -= parent[v]; } bool find(int u, int v) { return root(u) == root(v); } - int root(int u) { return parent[u] < 0 ? u : parent[u] = root(parent[u]); } + int root(int u) { while (parent[u] >= 0) u = parent[u]; return u; } int size(int u) { return -parent[root(u)]; } }; - struct OfflineDynamicConnectivity { int n; UndoableUnionFind uf;