From 892099eaa17f0fd4b804858ee34d6f1b8bc522e9 Mon Sep 17 00:00:00 2001 From: Manoj Pandey Date: Sat, 10 Oct 2015 17:39:27 +0530 Subject: [PATCH 1/9] added template --- template.cpp | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 template.cpp diff --git a/template.cpp b/template.cpp new file mode 100644 index 0000000..aa8a460 --- /dev/null +++ b/template.cpp @@ -0,0 +1,133 @@ +/* +Author: Manoj Pandey +Codechef, Codeforces, Spoj @ manojpandey +*/ + +//Includes + +#include +#include +#include +#include +#include +#include +#include +#include // istringstream>> ostring stream<< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +//Typedefs + +typedef long long ll; +typedef long double ld; +typedef unsigned long long ull; +typedef vector vi; +typedef vector vvi; +typedef vector vs; +typedef vector vll; +typedef vector > vpii; +typedef vector > vpll; +typedef pair pii; +typedef pair pll; +typedef istringstream iss; +typedef ostringstream oss; + +//Defines + +#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i)) +#define fu(i,a,n) for(int (i)=(int)(a);(i)<=(int)(n);++(i)) +#define fd(i,n,a) for(int (i)=(int)(n);(i)<=(int)(a);--(i)) +#define all(c) ((c).begin(),(c).end()) +#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it) +#define tr(c,i) for(typeof((c).begin() i = (c).begin(); i != (c).end(); i++) //Travelling Iterator +#define pb push_back +#define mp make_pair +#define ff first +#define ss second +#define mset(m,v) memset(m,v,sizeof(m)) +#define ln length() +#define sz(a) int((a).size()) +#define gi(n) scanf("%d",&n) +#define gl(n) cin >> n +#define pi(n) printf("%d",n) +#define pl(n) cout << n +#define ps printf(" ") +#define pn printf("\n") +#define imax numeric_limits::max() +#define imin numeric_limits::min() +#define lmax numeric_limits::max() +#define lmin numeric_limits::min() +#define present(c,x) ((c).find(x) != (c).end()) // for all other containers +#define cpresent(c,x) (find(all(c),x) != (c).end()) // for vector +#define getchar getchar_unlocked +#define putchar putchar_unlocked + +#if defined(_MSC_VER) || __cplusplus > 199711L +#define aut(r,v) auto r = (v) +#else +#define aut(r,v) typeof(v) r = (v) +#endif + +#define EPS (1e-9) +#define INF 0x3f3f3f3f +#define INFL 0x3f3f3f3f3f3f3f3fLL +#define MAX 111111 +#define MOD 1000000007 + +template inline void amin(T &x, U y) { if(y < x) x = y; } +template inline void amax(T &x, U y) { if(x < y) x = y; } + +inline void fastRead_int(int *a) { + register char c=0; + while (c<33) c=getchar_unlocked(); + *a=0; + while (c>33) { + *a=*a*10+c-'0'; + c=getchar_unlocked(); + } +} + +inline void fastRead_string(char *str) { + register char c=0; + register int i = 0; + while (c < 33) + c = getchar_unlocked(); + while (c > 65) { + str[i] = c; + c = getchar_unlocked(); + i = i + 1; + } + + str[i] = '\0'; +} + +inline void fastWrite(int a) { + char snum[20]; + int i=0; + do { + snum[i++]=a%10+48; + a=a/10; + } while(a!=0); + + i--; + while(i >= 0) putchar(snum[i--]); +} + +int main () { + + return 0; +} \ No newline at end of file From 5103a046883b06bdc6ff6b724256547cbf24443e Mon Sep 17 00:00:00 2001 From: Manoj Pandey Date: Sat, 10 Oct 2015 19:01:23 +0530 Subject: [PATCH 2/9] added algo implementations --- Graph Algorithms/BellmanFord.cpp | 75 ++++++++ Graph Algorithms/BipartiteMatchingKuhn.cpp | 75 ++++++++ Graph Algorithms/BridgesSearch.cpp | 88 ++++++++++ Graph Algorithms/CutpointsSearch.cpp | 91 ++++++++++ Graph Algorithms/DijkstraHeap.cpp | 94 ++++++++++ Graph Algorithms/DijkstraSet.cpp | 93 ++++++++++ Graph Algorithms/Dinic.cpp | 146 ++++++++++++++++ Graph Algorithms/EulerianCycle.cpp | 116 ++++++++++++ Graph Algorithms/FloydWarshall.cpp | 62 +++++++ Graph Algorithms/FordFulkerson.cpp | 104 +++++++++++ Graph Algorithms/HLD.cpp | 194 +++++++++++++++++++++ Graph Algorithms/HungarianMatching.cpp | 81 +++++++++ Graph Algorithms/LCABinary.cpp | 112 ++++++++++++ Graph Algorithms/LCAHLD.cpp | 146 ++++++++++++++++ Graph Algorithms/MinCostDijkstra.cpp | 186 ++++++++++++++++++++ Graph Algorithms/MinCostDijkstraHeap.cpp | 188 ++++++++++++++++++++ Graph Algorithms/MinCostFB.cpp | 135 ++++++++++++++ 17 files changed, 1986 insertions(+) create mode 100644 Graph Algorithms/BellmanFord.cpp create mode 100644 Graph Algorithms/BipartiteMatchingKuhn.cpp create mode 100644 Graph Algorithms/BridgesSearch.cpp create mode 100644 Graph Algorithms/CutpointsSearch.cpp create mode 100644 Graph Algorithms/DijkstraHeap.cpp create mode 100644 Graph Algorithms/DijkstraSet.cpp create mode 100644 Graph Algorithms/Dinic.cpp create mode 100644 Graph Algorithms/EulerianCycle.cpp create mode 100644 Graph Algorithms/FloydWarshall.cpp create mode 100644 Graph Algorithms/FordFulkerson.cpp create mode 100644 Graph Algorithms/HLD.cpp create mode 100644 Graph Algorithms/HungarianMatching.cpp create mode 100644 Graph Algorithms/LCABinary.cpp create mode 100644 Graph Algorithms/LCAHLD.cpp create mode 100644 Graph Algorithms/MinCostDijkstra.cpp create mode 100644 Graph Algorithms/MinCostDijkstraHeap.cpp create mode 100644 Graph Algorithms/MinCostFB.cpp diff --git a/Graph Algorithms/BellmanFord.cpp b/Graph Algorithms/BellmanFord.cpp new file mode 100644 index 0000000..dcf1540 --- /dev/null +++ b/Graph Algorithms/BellmanFord.cpp @@ -0,0 +1,75 @@ +/************************************************************************************** + + Bellman-Ford algorithm finding shortest distances from a single vertex + in graph. Works in O(N*M) + + Based on problem 178 from informatics.mccme.ru + http://informatics.mccme.ru/mod/statements/view3.php?id=260&chapterid=178#1 + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105; +const int INF = 30000; + +struct edge { + int from, to; + int w; +}; + +int n, m; +int dist[MAXN]; +vector e; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &m); + + for (int i = 1; i <= m; i++) { + edge curEdge; + scanf("%d %d %d", &curEdge.from, &curEdge.to, &curEdge.w); + e.push_back(curEdge); + } + + for (int i = 1; i <= n; i++) + dist[i] = INF; + dist[1] = 0; + + for (int i = 1; i <= n; i++) { + bool changed = false; + for (int j = 0; j < m; j++) { + int from = e[j].from, to = e[j].to, w = e[j].w; + if (dist[from] != INF && dist[from] + w < dist[to]) { + dist[to] = dist[from] + w; + changed = true; + } + } + if (!changed) + break; + } + + for (int i = 1; i <= n; i++) + printf("%d ", dist[i]); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/BipartiteMatchingKuhn.cpp b/Graph Algorithms/BipartiteMatchingKuhn.cpp new file mode 100644 index 0000000..964bb8f --- /dev/null +++ b/Graph Algorithms/BipartiteMatchingKuhn.cpp @@ -0,0 +1,75 @@ +/************************************************************************************** + + Kuhn algorithm for maximum matching in bipartite graph. Works in O(N * M) + More about it: http://e-maxx.ru/algo/kuhn_matching + Based on problem 1683 from informatics.mccme.ru: + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=1683 + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105; + +int n, m; +vector g[MAXN]; +bool used[MAXN]; +int mt[MAXN]; +int ans; + +bool kuhn(int v) { + if (used[v]) + return false; + used[v] = true; + for (int i = 0; i < (int) g[v].size(); i++) { + int to = g[v][i]; + if (mt[to] == 0 || kuhn(mt[to])) { + mt[to] = v; + return true; + } + } + return false; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &m); + + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + int can; + scanf("%d", &can); + if (can) + g[i].push_back(j); + } + } + + for (int i = 1; i <= n; i++) { + memset(used, 0, sizeof(used)); + if (kuhn(i)) + ans++; + } + + printf("%d\n", ans); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/BridgesSearch.cpp b/Graph Algorithms/BridgesSearch.cpp new file mode 100644 index 0000000..78ff68b --- /dev/null +++ b/Graph Algorithms/BridgesSearch.cpp @@ -0,0 +1,88 @@ +/************************************************************************************** + + Algorithm for finding all bridges in the graph (edges, after removal of + which graph divides into several components). O(M) + + Based on problem C from here: http://codeforces.ru/gym/100083 + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +int n, m; +vector g[MAXN]; +vector ind[MAXN]; +int tin[MAXN], mn[MAXN]; +bool used[MAXN]; +vector bridges; +int timer; + +void dfs(int v, int par = -1) { + used[v] = true; + timer++; + tin[v] = timer; + mn[v] = tin[v]; + + for (int i = 0; i < (int) g[v].size(); i++) { + int to = g[v][i]; + if (!used[to]) { + dfs(to, v); + if (mn[to] == tin[to]) { + bridges.push_back(ind[v][i]); + } + mn[v] = min(mn[v], mn[to]); + } + else if (to != par) { + mn[v] = min(mn[v], mn[to]); + } + } +} + +int main() { + assert(freopen("bridges.in","r",stdin)); + assert(freopen("bridges.out","w",stdout)); + + scanf("%d %d", &n, &m); + + for (int i = 1; i <= m; i++) { + int from, to; + scanf("%d %d", &from, &to); + + g[from].push_back(to); + ind[from].push_back(i); + + g[to].push_back(from); + ind[to].push_back(i); + } + + for (int i = 1; i <= n; i++) + if (!used[i]) + dfs(i); + + sort(bridges.begin(), bridges.end()); + + printf("%d\n", (int) bridges.size()); + for (int i = 0; i < (int) bridges.size(); i++) + printf("%d\n", bridges[i]); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/CutpointsSearch.cpp b/Graph Algorithms/CutpointsSearch.cpp new file mode 100644 index 0000000..3f12347 --- /dev/null +++ b/Graph Algorithms/CutpointsSearch.cpp @@ -0,0 +1,91 @@ +/************************************************************************************** + + Algorithm for finding all cutpoints in the graph (vertices, after removal of + which graph divides into several components). O(M) + + Based on problem D from here: http://codeforces.ru/gym/100083 + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +int n, m; +vector g[MAXN]; +int tin[MAXN], mn[MAXN]; +bool used[MAXN]; +vector cutVertices; +int timer; + +void dfs(int v, int par = -1) { + used[v] = true; + timer++; + tin[v] = timer; + mn[v] = tin[v]; + + int childNum = 0; + bool isCutVertex = false; + + for (int i = 0; i < (int) g[v].size(); i++) { + int to = g[v][i]; + if (!used[to]) { + childNum++; + dfs(to, v); + if (par != -1 && mn[to] >= tin[v] && !isCutVertex) { + isCutVertex = true; + cutVertices.push_back(v); + } + mn[v] = min(mn[v], mn[to]); + } + else if (to != par) { + mn[v] = min(mn[v], tin[to]); + } + } + + if (par == -1 && childNum > 1) + cutVertices.push_back(v); +} + +int main() { + assert(freopen("points.in","r",stdin)); + assert(freopen("points.out","w",stdout)); + + scanf("%d %d", &n, &m); + + for (int i = 1; i <= m; i++) { + int from, to; + scanf("%d %d", &from, &to); + g[from].push_back(to); + g[to].push_back(from); + } + + for (int i = 1; i <= n; i++) + if (!used[i]) + dfs(i); + + sort(cutVertices.begin(), cutVertices.end()); + + printf("%d\n", (int) cutVertices.size()); + for (int i = 0; i < (int) cutVertices.size(); i++) + printf("%d\n", cutVertices[i]); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/DijkstraHeap.cpp b/Graph Algorithms/DijkstraHeap.cpp new file mode 100644 index 0000000..4b998a7 --- /dev/null +++ b/Graph Algorithms/DijkstraHeap.cpp @@ -0,0 +1,94 @@ +/************************************************************************************** + + Dijkstra on heap for sparse graphs - O(MlogM) + Based on problem 20C from codeforces: http://codeforces.ru/contest/20/problem/C + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const long long INF = (long long) 1e12; +const int MAXN = 105000; + +struct edge { + int to, w; +}; + +int n, m; +vector g[MAXN]; +long long dist[MAXN]; +int par[MAXN]; +priority_queue < pair > q; +vector ans; +edge e; + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + scanf("%d %d", &n, &m); + for (int i = 1; i <= m; i++) { + int a, b, w; + scanf("%d %d %d", &a, &b, &w); + e.to = b; e.w = w; + g[a].push_back(e); + e.to = a; + g[b].push_back(e); + } + + q.push(make_pair(0, 1)); + for (int i = 2; i <= n; i++) { + dist[i] = INF; + q.push(make_pair(-INF, i)); + } + + while (!q.empty()) { + int cur = q.top().second; + long long cur_dist = -q.top().first; + q.pop(); + if (cur_dist > dist[cur]) + continue; + for (int i = 0; i < (int) g[cur].size(); i++) { + int to = g[cur][i].to, w = g[cur][i].w; + if (cur_dist + w < dist[to]) { + dist[to] = cur_dist + w; + par[to] = cur; + q.push(make_pair(-dist[to], to)); + } + } + } + + if (dist[n] == INF) { + printf("-1"); + return 0; + } + + int cur = n; + while (par[cur] != 0) { + ans.push_back(cur); + cur = par[cur]; + } + ans.push_back(1); + + reverse(ans.begin(), ans.end()); + for (int i = 0; i < (int) ans.size(); i++) + printf("%d ", ans[i]); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/DijkstraSet.cpp b/Graph Algorithms/DijkstraSet.cpp new file mode 100644 index 0000000..107486b --- /dev/null +++ b/Graph Algorithms/DijkstraSet.cpp @@ -0,0 +1,93 @@ +/************************************************************************************** + + Dijkstra on set for sparse graphs - O(MlogM). Slower than heap version + Based on problem 20C from codeforces: http://codeforces.ru/contest/20/problem/C + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const long long INF = (long long)1e12; +const int MAXN = 105000; + +struct edge { + int to, w; +}; + +int n, m; +vector g[MAXN]; +long long dist[MAXN]; +int par[MAXN]; +set < pair > s; +vector ans; +edge e; + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + scanf("%d %d", &n, &m); + for (int i = 1; i <= m; i++) { + int a, b, w; + scanf("%d %d %d", &a, &b, &w); + e.to = b; e.w = w; + g[a].push_back(e); + e.to = a; + g[b].push_back(e); + } + + s.insert(make_pair(0, 1)); + for (int i = 2; i <= n; i++) { + dist[i] = INF; + s.insert(make_pair(INF, i)); + } + + while (!s.empty()) { + int cur = s.begin()->second; + long long cur_dist = s.begin()->first; + s.erase(s.begin()); + for (int i = 0; i < (int) g[cur].size(); i++) { + int to = g[cur][i].to, w = g[cur][i].w; + if (cur_dist + w < dist[to]) { + s.erase(make_pair(dist[to], to)); + dist[to] = cur_dist + w; + par[to] = cur; + s.insert(make_pair(dist[to], to)); + } + } + } + + if (dist[n] == INF) { + printf("-1"); + return 0; + } + + int cur = n; + while (par[cur] != 0) { + ans.push_back(cur); + cur = par[cur]; + } + ans.push_back(1); + + reverse(ans.begin(), ans.end()); + for (int i = 0; i < (int) ans.size(); i++) + printf("%d ", ans[i]); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/Dinic.cpp b/Graph Algorithms/Dinic.cpp new file mode 100644 index 0000000..14c0003 --- /dev/null +++ b/Graph Algorithms/Dinic.cpp @@ -0,0 +1,146 @@ +/******************************************************************************** + + MaxFlow Dinic algorithm with scaling. + O(N * M * log(MC)), where MC is maximum edge capacity. + + Based on problem 2784 from informatics.mccme.ru + http://informatics.mccme.ru/mod/statements/view3.php?chapterid=2784#1 + +********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +struct edge { + int a, b, f, c; +}; + +const int inf = 1000 * 1000 * 1000; +const int MAXN = 1050; + +int n, m; +vector e; +int pt[MAXN]; // very important performance trick +vector g[MAXN]; +long long flow = 0; +queue q; +int d[MAXN]; +int lim; +int s, t; + +void add_edge(int a, int b, int c) { + edge ed; + + //keep edges in vector: e[ind] - direct edge, e[ind ^ 1] - back edge + + ed.a = a; ed.b = b; ed.f = 0; ed.c = c; + g[a].push_back(e.size()); + e.push_back(ed); + + ed.a = b; ed.b = a; ed.f = c; ed.c = c; + g[b].push_back(e.size()); + e.push_back(ed); +} + +bool bfs() { + for (int i = s; i <= t; i++) + d[i] = inf; + d[s] = 0; + q.push(s); + while (!q.empty() && d[t] == inf) { + int cur = q.front(); q.pop(); + for (size_t i = 0; i < g[cur].size(); i++) { + int id = g[cur][i]; + int to = e[id].b; + + //printf("cur = %d id = %d a = %d b = %d f = %d c = %d\n", cur, id, e[id].a, e[id].b, e[id].f, e[id].c); + + if (d[to] == inf && e[id].c - e[id].f >= lim) { + d[to] = d[cur] + 1; + q.push(to); + } + } + } + while (!q.empty()) + q.pop(); + return d[t] != inf; +} + +bool dfs(int v, int flow) { + if (flow == 0) + return false; + if (v == t) { + //cout << v << endl; + return true; + } + for (; pt[v] < g[v].size(); pt[v]++) { + int id = g[v][pt[v]]; + int to = e[id].b; + + //printf("v = %d id = %d a = %d b = %d f = %d c = %d\n", v, id, e[id].a, e[id].b, e[id].f, e[id].c); + + if (d[to] == d[v] + 1 && e[id].c - e[id].f >= flow) { + int pushed = dfs(to, flow); + if (pushed) { + e[id].f += flow; + e[id ^ 1].f -= flow; + return true; + } + } + } + return false; +} + +void dinic() { + for (lim = (1 << 30); lim >= 1;) { + if (!bfs()) { + lim >>= 1; + continue; + } + + for (int i = s; i <= t; i++) + pt[i] = 0; + + int pushed; + + while (pushed = dfs(s, lim)) { + flow = flow + lim; + } + + //cout << flow << endl; + } +} + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + scanf("%d %d", &n, &m); + + s = 1; t = n; + + for (int i = 1; i <= m; i++) { + int a, b, c; + scanf("%d %d %d", &a, &b, &c); + add_edge(a, b, c); + } + + dinic(); + + cout << flow << endl; + + return 0; +} diff --git a/Graph Algorithms/EulerianCycle.cpp b/Graph Algorithms/EulerianCycle.cpp new file mode 100644 index 0000000..84e02f0 --- /dev/null +++ b/Graph Algorithms/EulerianCycle.cpp @@ -0,0 +1,116 @@ +/************************************************************************************ + + Algorithm for finding Eulerian path/cycle (path that visits every edge + exactly once). O(M). + + Based on problem 1704 from informatics.mccme.ru + http://informatics.mccme.ru/mod/statements/view3.php?chapterid=1704 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1050; + +struct edge { + int to; + int gate1, gate2; + bool used; +}; + +int n; +vector e; +vector g[MAXN]; +int pos[MAXN]; +edge tmp; +bool used[MAXN]; +vector ans; + +/* + Eulerian walk search. Criterias are neglected in this problem. + Eulerian cycle criteria - all vertices have even degree. + Eulerian path criteria - maximum 2 vertices have odd degree. Path is found + from cycle: add extra edge, find cycle, remove edge. +*/ +void dfs(int v) { + for (; pos[v] < (int) g[v].size(); pos[v]++) { + int ind = g[v][pos[v]]; + int to = e[ind].to; + if (e[ind].used) + continue; + e[ind].used = true; e[ind ^ 1].used = true; + dfs(e[ind].to); + } + ans.push_back(v); + used[v] = true; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= 2 * n; i++) { + int gate1, gate2; + int from, to; + scanf("%d %d", &gate1, &gate2); + from = (gate1 + 3) / 4; to = (gate2 + 3) / 4; + + tmp.used = false; + tmp.to = to; tmp.gate1 = gate1; tmp.gate2 = gate2; + e.push_back(tmp); + g[from].push_back( (int) e.size() - 1 ); + + tmp.to = from; tmp.gate1 = gate2; tmp.gate2 = gate1; + e.push_back(tmp); + g[to].push_back( (int) e.size() - 1 ); + } + + dfs(1); + + for (int i = 1; i <= n; i++) { + if (!used[i]) { + puts("No"); + return 0; + } + } + + puts("Yes"); + + /* + Ans contains all vertices in the right order for Eulerian walk. + Output specific to this problem. + */ + reverse(ans.begin(), ans.end()); + for (int i = 0; i < (int) ans.size() - 1; i++) { + int from = ans[i], to = ans[i + 1]; + for (int j = 0; j < (int) g[from].size(); j++) { + int ind = g[from][j]; + if (e[ind].to == to && e[ind].used) { + printf("%d %d ", e[ind].gate1, e[ind].gate2); + e[ind].used = false; + e[ind ^ 1].used = false; + break; + } + } + } + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/FloydWarshall.cpp b/Graph Algorithms/FloydWarshall.cpp new file mode 100644 index 0000000..8d1cdb8 --- /dev/null +++ b/Graph Algorithms/FloydWarshall.cpp @@ -0,0 +1,62 @@ +/************************************************************************************** + + Floyd-Warshall algorithm finding shortest distance between all + pairs of vertices in graph. Works in O(N^3) + + Based on problem 95 from informatics.mccme.ru + http://informatics.mccme.ru/mod/statements/view.php?id=218#1 + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 55; +const int INF = (int) 1e9; + +int n; +int s, t; +int d[MAXN][MAXN]; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d %d", &n, &s, &t); + + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) { + scanf("%d", &d[i][j]); + if (d[i][j] == -1) + d[i][j] = INF; + } + + for (int k = 1; k <= n; k++) + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + if (d[i][k] + d[k][j] < d[i][j]) + d[i][j] = d[i][k] + d[k][j]; + + if (d[s][t] == INF) + printf("-1\n"); + else + printf("%d\n", d[s][t]); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/FordFulkerson.cpp b/Graph Algorithms/FordFulkerson.cpp new file mode 100644 index 0000000..99cf517 --- /dev/null +++ b/Graph Algorithms/FordFulkerson.cpp @@ -0,0 +1,104 @@ +/******************************************************************************** + + MaxFlow Ford-Fulkerson algorithm. O(M|f|), |f| - maxflow value + Based on problem 2783 from informatics.mccme.ru + http://informatics.mccme.ru/mod/statements/view3.php?chapterid=2783#1 + +********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1050; +const int INF = (int) 1e9; + +struct edge { + int from, to, f, cap; +}; + +int n, m; +vector e; +vector g[MAXN]; +bool used[MAXN]; +int s, t; +int ans; + +void addEdge(int from, int to, int cap) { + edge ed; + + ed.from = from; ed.to = to; ed.f = 0; ed.cap = cap; + e.push_back(ed); + g[from].push_back((int) e.size() - 1); + + ed.from = to; ed.to = from; ed.f = cap; ed.cap = cap; + e.push_back(ed); + g[to].push_back((int) e.size() - 1); +} + +int pushFlow(int v, int flow = INF) { + used[v] = true; + if (v == t) + return flow; + + for (int i = 0; i < (int) g[v].size(); i++) { + int ind = g[v][i]; + int to = e[ind].to; + int f = e[ind].f; + int cap = e[ind].cap; + + if (used[to] || cap - f == 0) + continue; + + int pushed = pushFlow(to, min(flow, cap - f)); + if (pushed > 0) { + e[ind].f += pushed; + e[ind ^ 1].f -= pushed; + return pushed; + } + } + + return 0; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &m); + + s = 1; t = n; + + for (int i = 1; i <= m; i++) { + int from, to, cap; + scanf("%d %d %d", &from, &to, &cap); + addEdge(from, to, cap); + } + + while (true) { + memset(used, 0, sizeof(used)); + int add = pushFlow(s); + if (add == 0) + break; + ans += add; + } + + printf("%d\n", ans); + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/HLD.cpp b/Graph Algorithms/HLD.cpp new file mode 100644 index 0000000..a9a2ec6 --- /dev/null +++ b/Graph Algorithms/HLD.cpp @@ -0,0 +1,194 @@ +/************************************************************************************ + + Heavy-light decomposition with segment trees in paths. + Used for finding maximum on the path between two vertices. + O(N) on building, O(logN ^ 2) on query. + + Based on problem 1553 from acm.timus.ru + http://acm.timus.ru/problem.aspx?space=1&num=1553 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +struct SegmentTree { + int * tree; + int size; + + void init(int sz) { + tree = new int[4 * sz]; + memset(tree, 0, 4 * sz * sizeof(int)); + size = sz; + } + + int getMax(int v, int from, int to, int l, int r) { + if (l > to || r < from) + return 0; + if (from == l && to == r) + return tree[v]; + int mid = (from + to) / 2; + int res = getMax(v * 2, from, mid, l, min(r, mid)); + res = max(res, getMax(v * 2 + 1, mid + 1, to, max(l, mid + 1), r)); + return res; + } + + int getMax(int l, int r) { + return getMax(1, 1, size, l, r); + } + + void update(int v, int from, int to, int pos, int val) { + if (pos > to || pos < from) + return; + if (from == pos && to == pos) { + tree[v] = val; + return; + } + int mid = (from + to) / 2; + update(v * 2, from, mid, pos, val); + update(v * 2 + 1, mid + 1, to, pos, val); + tree[v] = max(tree[v * 2], tree[v * 2 + 1]); + } + + void update(int pos, int val) { + update(1, 1, size, pos, val); + } +}; + +int n, qn; +char q; +int a, b; +int timer; +int sz[MAXN]; +int tin[MAXN], tout[MAXN]; +int val[MAXN]; +vector g[MAXN]; +int p[MAXN]; +int chain[MAXN], chainRoot[MAXN]; +int chainSize[MAXN], chainPos[MAXN]; +int chainNum; +SegmentTree tree[MAXN]; + +bool isHeavy(int from, int to) { + return sz[to] * 2 >= sz[from]; +} + +void dfs(int v, int par = -1) { + timer++; + tin[v] = timer; + p[v] = par; + sz[v] = 1; + + for (int i = 0; i < (int) g[v].size(); i++) { + int to = g[v][i]; + if (to == par) + continue; + dfs(to, v); + sz[v] += sz[to]; + } + + timer++; + tout[v] = timer; +} + +int newChain(int root) { + chainNum++; + chainRoot[chainNum] = root; + return chainNum; +} + +void buildHLD(int v, int curChain) { + chain[v] = curChain; + chainSize[curChain]++; + chainPos[v] = chainSize[curChain]; + + for (int i = 0; i < g[v].size(); i++) { + int to = g[v][i]; + if (p[v] == to) + continue; + if (isHeavy(v, to)) + buildHLD(to, curChain); + else + buildHLD(to, newChain(to)); + } +} + +bool isParent(int a, int b) { + return tin[a] <= tin[b] && tout[a] >= tout[b]; +} + +int getMax(int a, int b) { + int res = 0; + while (true) { + int curChain = chain[a]; + if (isParent(chainRoot[curChain], b)) + break; + res = max(res, tree[curChain].getMax(1, chainPos[a])); + a = p[chainRoot[curChain]]; + } + while (true) { + int curChain = chain[b]; + if (isParent(chainRoot[curChain], a)) + break; + res = max(res, tree[curChain].getMax(1, chainPos[b])); + b = p[chainRoot[curChain]]; + } + int from = chainPos[a], to = chainPos[b]; + if (from > to) + swap(from, to); + res = max(res, tree[chain[a]].getMax(from, to)); + return res; +} + + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i < n; i++) { + int from, to; + scanf("%d %d", &from, &to); + g[from].push_back(to); + g[to].push_back(from); + } + + dfs(1); + buildHLD(1, newChain(1)); + + for (int i = 1; i <= chainNum; i++) { + tree[i].init(chainSize[i]); + } + + scanf("%d\n", &qn); + for (int i = 1; i <= qn; i++) { + scanf("%c %d %d\n", &q, &a, &b); + if (q == 'I') { + val[a] += b; + tree[chain[a]].update(chainPos[a], val[a]); + } + else { + printf("%d\n", getMax(a, b)); + } + } + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/HungarianMatching.cpp b/Graph Algorithms/HungarianMatching.cpp new file mode 100644 index 0000000..b91879e --- /dev/null +++ b/Graph Algorithms/HungarianMatching.cpp @@ -0,0 +1,81 @@ +/*************************************************************************************************** + + Hungarian matching algorithm - O(N ^ 3) + Based on problem http://informatics.mccme.ru/moodle/mod/statements/view3.php?chapterid=394#1 + Algorithm realization based on http://e-maxx.ru/algo/assignment_hungary + +***************************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105; +const int INF = 1000 * 1000 * 1000; + +int n; +int a[MAXN][MAXN]; +int u[MAXN], v[MAXN], link[MAXN], par[MAXN], used[MAXN], minval[MAXN]; + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + scanf("%d", &n); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + scanf("%d", &a[i][j]); + + for (int i = 1; i <= n; i++) { + for (int j = 0; j < MAXN; j++) { + used[j] = false; + minval[j] = INF; + } + int j_cur = 0; + par[j_cur] = i; + do { + used[j_cur] = true; + int j_next, delta = INF, i_cur = par[j_cur]; + for (int j = 0; j <= n; j++) + if (!used[j]) { + int cur = a[i_cur][j] - u[i_cur] - v[j]; + if (cur < minval[j]) { + minval[j] = cur; link[j] = j_cur; + } + if (minval[j] < delta) { + delta = minval[j]; j_next = j; + } + } + for (int j = 0; j <= n; j++) + if (used[j]) { + u[par[j]] += delta; v[j] -= delta; + } + else { + minval[j] -= delta; + } + j_cur = j_next; + } while (par[j_cur]); + do { + int j_prev = link[j_cur]; + par[j_cur] = par[j_prev]; + j_cur = j_prev; + } while (j_cur > 0); + } + + printf("%d", -v[0]); + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/LCABinary.cpp b/Graph Algorithms/LCABinary.cpp new file mode 100644 index 0000000..30b7e3a --- /dev/null +++ b/Graph Algorithms/LCABinary.cpp @@ -0,0 +1,112 @@ +/************************************************************************************ + + Finding LCA (Least common ancestor) of two vertices in the tree. + Uses dp calculated on powers of 2. + O(NlogN) for preprocessing, O(logN) on query. + + Based on problem 111796 from informatics.mccme.ru + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=111796 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 405000; +const int MAXLOG = 22; + +int n, qn; +vector g[MAXN]; +int dp[MAXN][MAXLOG]; +int tin[MAXN], tout[MAXN]; +int timer; + +int a[MAXN]; +int x, y, z; +long long ans; + +void dfs(int v, int par = 1) { + timer++; + tin[v] = timer; + + dp[v][0] = par; + for (int i = 1; i < MAXLOG; i++) + dp[v][i] = dp[dp[v][i - 1]][i - 1]; + + for (int i = 0; i < (int) g[v].size(); i++) { + int to = g[v][i]; + if (to != par) + dfs(to, v); + } + + timer++; + tout[v] = timer; +} + +bool isParent(int a, int b) { + return tin[a] <= tin[b] && tout[a] >= tout[b]; +} + +int lca(int a, int b) { + if (isParent(a, b)) + return a; + if (isParent(b, a)) + return b; + for (int i = MAXLOG - 1; i >= 0; i--) { + if (!isParent(dp[a][i], b)) + a = dp[a][i]; + } + return dp[a][0]; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &qn); + + for (int i = 1; i < n; i++) { + int par; + scanf("%d", &par); + par++; + g[i + 1].push_back(par); + g[par].push_back(i + 1); + } + + dfs(1); + + // Reference problem input format + scanf("%d %d", &a[1], &a[2]); + scanf("%d %d %d", &x, &y, &z); + for (int i = 3; i <= 2 * qn; i++) { + a[i] = (1ll * x * a[i - 2] + 1ll * y * a[i - 1] + 1ll * z) % n; + } + + int q1 = a[1], q2 = a[2]; + for (int i = 1; i <= qn; i++) { + int cur = lca(q1 + 1, q2 + 1) - 1; + ans += cur; + q1 = (a[2 * (i + 1) - 1] + cur) % n; + q2 = a[2 * (i + 1)]; + } + + cout << ans << endl; + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/LCAHLD.cpp b/Graph Algorithms/LCAHLD.cpp new file mode 100644 index 0000000..39891f9 --- /dev/null +++ b/Graph Algorithms/LCAHLD.cpp @@ -0,0 +1,146 @@ +/************************************************************************************ + + Finding LCA (Least common ancestor) of two vertices in the tree. + Uses heavy-light decomposition. + O(N) for preprocessing, O(logN) on query. + + Based on problem 111796 from informatics.mccme.ru + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=111796 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +int n, qn; +vector g[MAXN]; +int tin[MAXN], tout[MAXN]; +int p[MAXN]; +int sz[MAXN]; +int chain[MAXN], chainRoot[MAXN]; +int chainNum; +int timer; + +int a[2 * MAXN]; +int x, y, z; + +long long ans; + +void dfs(int v, int par = -1) { + timer++; + tin[v] = timer; + p[v] = par; + sz[v] = 1; + + for (int i = 0; i < (int) g[v].size(); i++) { + int to = g[v][i]; + if (to == par) + continue; + dfs(to, v); + sz[v] += sz[to]; + } + + timer++; + tout[v] = timer; +} + +bool isHeavy(int from, int to) { + return 2 * sz[to] >= sz[from]; +} + +int newChain(int root) { + chainNum++; + chainRoot[chainNum] = root; + return chainNum; +} + +void buildHLD(int v, int curChain) { + chain[v] = curChain; + for (int i = 0; i < g[v].size(); i++) { + int to = g[v][i]; + if (to == p[v]) + continue; + if (isHeavy(v, to)) + buildHLD(to, curChain); + else + buildHLD(to, newChain(to)); + } +} + +bool isParent(int a, int b) { + return tin[a] <= tin[b] && tout[a] >= tout[b]; +} + +int lca(int a, int b) { + while (true) { + int curChain = chain[a]; + if (isParent(chainRoot[curChain], b)) + break; + a = p[chainRoot[curChain]]; + } + while (true) { + int curChain = chain[b]; + if (isParent(chainRoot[curChain], a)) + break; + b = p[chainRoot[curChain]]; + } + if (isParent(a, b)) + return a; + else + return b; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &qn); + + for (int i = 1; i < n; i++) { + int par; + scanf("%d", &par); + par++; + g[i + 1].push_back(par); + g[par].push_back(i + 1); + } + + dfs(1); + buildHLD(1, newChain(1)); + + // Reference problem input format + scanf("%d %d", &a[1], &a[2]); + scanf("%d %d %d", &x, &y, &z); + for (int i = 3; i <= 2 * qn; i++) { + a[i] = (1ll * x * a[i - 2] + 1ll * y * a[i - 1] + 1ll * z) % n; + } + + int q1 = a[1], q2 = a[2]; + for (int i = 1; i <= qn; i++) { + int cur = lca(q1 + 1, q2 + 1) - 1; + ans += cur; + q1 = (a[2 * (i + 1) - 1] + cur) % n; + q2 = a[2 * (i + 1)]; + } + + cout << ans << endl; + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/MinCostDijkstra.cpp b/Graph Algorithms/MinCostDijkstra.cpp new file mode 100644 index 0000000..79cc3df --- /dev/null +++ b/Graph Algorithms/MinCostDijkstra.cpp @@ -0,0 +1,186 @@ +/************************************************************************************ + + Min Cost Flow (or Min Cost Max Flow) algorithm with + Dijkstra algorithm (with potentials) as shortest path search method. + (Dijkstra for dense graphs running in O(N^2)) + + Works O(N ^ 5). Less on practice. + Runs in O(N ^ 3) for bipartite matching case. + + Based on problem 394 from informatics.mccme.ru + http://informatics.mccme.ru//mod/statements/view3.php?chapterid=394 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1050; +const long long INF = (long long) 1e15; + +struct edge { + int from, to; + int flow, cap; + long long cost; +}; + +int n; +int cost[MAXN][MAXN]; +vector e; +vector g[MAXN]; +long long phi[MAXN]; +long long dist[MAXN]; +bool used[MAXN]; +int par[MAXN]; +int edge_num; +int s = 0, t = MAXN - 1; + +void fordBellman() { + for (int i = s; i <= t; i++) + dist[i] = INF; + dist[s] = 0; + while (true) { + bool change = false; + for (int i = 0; i < edge_num; i++) { + int from = e[i].from, to = e[i].to; + if (e[i].flow == e[i].cap) + continue; + if (dist[from] == INF) + continue; + if (dist[to] > dist[from] + e[i].cost) { + dist[to] = dist[from] + e[i].cost; + change = true; + } + } + if (!change) + break; + } +} + +void dijkstra() { + for (int i = s; i <= t; i++) { + dist[i] = INF; + used[i] = false; + } + dist[s] = 0; + + for (int i = s; i <= t; i++) { + int cur = -1; + for (int j = s; j <= t; j++) + if (!used[j]) + if (cur == -1 || dist[j] < dist[cur]) + cur = j; + + used[cur] = true; + + for (int j = 0; j < (int) g[cur].size(); j++) { + int ind = g[cur][j]; + if (e[ind].flow == e[ind].cap) + continue; + int to = e[ind].to; + int w = e[ind].cost + phi[cur] - phi[to]; + if (dist[cur] + w < dist[to]) { + dist[to] = dist[cur] + w; + par[to] = ind; + } + } + } +} + +long long minCost(int flow) { + long long result = 0; + + fordBellman(); + for (int i = s; i <= t; i++) + phi[i] = dist[i]; + + while (true) { + + dijkstra(); + + if (dist[t] == INF) + return result; + + for (int i = s; i <= t; i++) + phi[i] = min(phi[i] + dist[i], INF); + + int push = flow; + int cur = t; + while (cur != s) { + edge tmp = e[par[cur]]; + int from = tmp.from, can_push = tmp.cap - tmp.flow; + push = min(push, can_push); + cur = from; + } + + flow -= push; + cur = t; + while (cur != s) { + edge tmp = e[par[cur]]; + int from = tmp.from; + e[par[cur]].flow += push; + e[par[cur] ^ 1].flow -= push; + result += 1ll * push * tmp.cost; + cur = from; + } + + if (flow == 0) + break; + } + return result; +} + +void addEdge(int from, int to, int cap, long long cost) { + edge tmp; + tmp.from = from; tmp.to = to; tmp.flow = 0; tmp.cap = cap; tmp.cost = cost; + e.push_back(tmp); + g[from].push_back(edge_num); + + tmp.from = to; tmp.to = from; tmp.flow = cap; tmp.cap = cap; tmp.cost = -cost; + e.push_back(tmp); + g[to].push_back(edge_num + 1); + + edge_num += 2; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + scanf("%d", &cost[i][j]); + + s = 0; t = 2 * n + 1; + + for (int i = 1; i <= n; i++) + addEdge(s, i, 1, 0); + + for (int i = n + 1; i <= 2 * n; i++) + addEdge(i, t, 1, 0); + + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + addEdge(i, n + j, 1, cost[i][j]); + + cout << minCost(n) << endl; + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/MinCostDijkstraHeap.cpp b/Graph Algorithms/MinCostDijkstraHeap.cpp new file mode 100644 index 0000000..7cd834d --- /dev/null +++ b/Graph Algorithms/MinCostDijkstraHeap.cpp @@ -0,0 +1,188 @@ +/************************************************************************************ + + Min Cost Flow (or Min Cost Max Flow) algorithm with + Dijkstra algorithm (with potentials) as shortest path search method. + (Dijkstra on heap for sparse graphs) + + Works (N * M ^ 2 * logN). Less on practice. + Runs in O(N ^ 3) for bipartite matching case. + + Based on problem 394 from informatics.mccme.ru + http://informatics.mccme.ru//mod/statements/view3.php?chapterid=394 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1050; +const long long INF = (long long) 1e15; + +struct edge { + int from, to; + int flow, cap; + long long cost; +}; + +int n; +int cost[MAXN][MAXN]; +vector e; +vector g[MAXN]; +long long phi[MAXN]; +priority_queue < pair < long long, int > > q; +long long dist[MAXN]; +int par[MAXN]; +int edge_num; +int s = 0, t = MAXN - 1; + +void fordBellman() { + for (int i = s; i <= t; i++) + dist[i] = INF; + dist[s] = 0; + while (true) { + bool change = false; + for (int i = 0; i < edge_num; i++) { + int from = e[i].from, to = e[i].to; + if (e[i].flow == e[i].cap) + continue; + if (dist[from] == INF) + continue; + if (dist[to] > dist[from] + e[i].cost) { + dist[to] = dist[from] + e[i].cost; + change = true; + } + } + if (!change) + break; + } +} + +void dijkstra() { + while (!q.empty()) + q.pop(); + for (int i = s; i <= t; i++) { + dist[i] = INF; + q.push(make_pair(-dist[i], i)); + } + dist[s] = 0; + q.push(make_pair(0, s)); + while (!q.empty()) { + int cur = q.top().second; + long long cur_dist = -q.top().first; + q.pop(); + if (cur_dist > dist[cur]) + continue; + if (dist[cur] == INF) + break; + for (int i = 0; i < (int) g[cur].size(); i++) { + int ind = g[cur][i]; + if (e[ind].flow == e[ind].cap) + continue; + int to = e[ind].to; + long long w = e[ind].cost + phi[cur] - phi[to]; + if (cur_dist + w < dist[to]) { + dist[to] = cur_dist + w; + par[to] = ind; + q.push(make_pair(-dist[to], to)); + } + } + } +} + +long long minCost(int flow) { + long long result = 0; + + fordBellman(); + for (int i = s; i <= t; i++) + phi[i] = dist[i]; + + while (true) { + + dijkstra(); + + if (dist[t] == INF) + return result; + + for (int i = s; i <= t; i++) + phi[i] = min(phi[i] + dist[i], INF); + + int push = flow; + int cur = t; + while (cur != s) { + edge tmp = e[par[cur]]; + int from = tmp.from, can_push = tmp.cap - tmp.flow; + push = min(push, can_push); + cur = from; + } + + flow -= push; + cur = t; + while (cur != s) { + edge tmp = e[par[cur]]; + int from = tmp.from; + e[par[cur]].flow += push; + e[par[cur] ^ 1].flow -= push; + result += 1ll * push * tmp.cost; + cur = from; + } + + if (flow == 0) + break; + } + return result; +} + +void addEdge(int from, int to, int cap, long long cost) { + edge tmp; + tmp.from = from; tmp.to = to; tmp.flow = 0; tmp.cap = cap; tmp.cost = cost; + e.push_back(tmp); + g[from].push_back(edge_num); + + tmp.from = to; tmp.to = from; tmp.flow = cap; tmp.cap = cap; tmp.cost = -cost; + e.push_back(tmp); + g[to].push_back(edge_num + 1); + + edge_num += 2; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + scanf("%d", &cost[i][j]); + + s = 0; t = 2 * n + 1; + + for (int i = 1; i <= n; i++) + addEdge(s, i, 1, 0); + + for (int i = n + 1; i <= 2 * n; i++) + addEdge(i, t, 1, 0); + + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + addEdge(i, n + j, 1, cost[i][j]); + + cout << minCost(n) << endl; + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/MinCostFB.cpp b/Graph Algorithms/MinCostFB.cpp new file mode 100644 index 0000000..beccb64 --- /dev/null +++ b/Graph Algorithms/MinCostFB.cpp @@ -0,0 +1,135 @@ +/************************************************************************************ + + Min Cost Flow (or Min Cost Max Flow) algorithm with + Ford-Bellman algorithm as shortest path search method. + Works O(N ^ 6). Less on practice. + Runs in O(N ^ 4) for bipartite matching case. + + Based on problem 394 from informatics.mccme.ru + http://informatics.mccme.ru//mod/statements/view3.php?chapterid=394 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1050; +const long long INF = (long long) 1e15; + +struct edge { + int from, to; + int flow, cap; + long long cost; +}; + +int n; +int cost[MAXN][MAXN]; +vector e; +long long dist[MAXN]; +int par[MAXN]; +int edge_num; +int s = 0, t = MAXN - 1; + +long long minCost(int flow) { + long long result = 0; + while (true) { + for (int i = s; i <= t; i++) + dist[i] = INF; + dist[s] = 0; + while (true) { + bool change = false; + for (int i = 0; i < edge_num; i++) { + int from = e[i].from, to = e[i].to; + if (e[i].flow == e[i].cap) + continue; + if (dist[from] == INF) + continue; + if (dist[to] > dist[from] + e[i].cost) { + dist[to] = dist[from] + e[i].cost; + par[to] = i; + change = true; + } + } + if (!change) + break; + } + + if (dist[t] == INF) + return result; + + int push = flow; + int cur = t; + while (cur != s) { + edge tmp = e[par[cur]]; + int from = tmp.from, can_push = tmp.cap - tmp.flow; + push = min(push, can_push); + cur = from; + } + + flow -= push; + cur = t; + while (cur != s) { + edge tmp = e[par[cur]]; + int from = tmp.from; + e[par[cur]].flow += push; + e[par[cur] ^ 1].flow -= push; + result += 1ll * push * tmp.cost; + cur = from; + } + + if (flow == 0) + break; + } + return result; +} + +void addEdge(int from, int to, int cap, long long cost) { + edge tmp; + tmp.from = from; tmp.to = to; tmp.flow = 0; tmp.cap = cap; tmp.cost = cost; + e.push_back(tmp); + tmp.from = to; tmp.to = from; tmp.flow = cap; tmp.cap = cap; tmp.cost = -cost; + e.push_back(tmp); + edge_num += 2; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + scanf("%d", &cost[i][j]); + + t = 2 * n + 1; + + for (int i = 1; i <= n; i++) + addEdge(s, i, 1, 0); + + for (int i = n + 1; i <= 2 * n; i++) + addEdge(i, t, 1, 0); + + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + addEdge(i, n + j, 1, cost[i][j]); + + cout << minCost(n) << endl; + + return 0; +} \ No newline at end of file From 297e5a77a8015e0038d997739cc63cfaf4be3b0e Mon Sep 17 00:00:00 2001 From: Manoj Pandey Date: Sat, 10 Oct 2015 19:03:13 +0530 Subject: [PATCH 3/9] added algo implementations --- .../ClosestPairOfPoints.cpp | 125 +++++ .../ClosestPairOfPointsNurlan.cpp | 94 ++++ Data Structures/CartesianTree.cpp | 123 +++++ Data Structures/CartesianTreeImplicitKeys.cpp | 158 ++++++ Data Structures/FenwickTree.cpp | 78 +++ Data Structures/FenwickTree2D.cpp | 81 +++ Data Structures/ImplicitSegmentTree.cpp | 97 ++++ Data Structures/QueueWithMinimum.cpp | 80 +++ Data Structures/SegmentTree(Assign-Sum).cpp | 120 +++++ Data Structures/SegmentTree.cpp | 97 ++++ Data Structures/SparseTable.cpp | 80 +++ Dynamic Programming/LIS.cpp | 80 +++ Number Theory/BigInt.cpp | 489 ++++++++++++++++++ Number Theory/CatalanNumbers.cpp | 81 +++ Number Theory/DiophantineEquation.cpp | 97 ++++ Number Theory/FFT.cpp | 126 +++++ Number Theory/Gauss.cpp | 117 +++++ Number Theory/NumberByPermutation.cpp | 66 +++ Number Theory/PermutationByNumber.cpp | 73 +++ .../MergeSort.cpp | 73 +++ .../QuickSort.cpp | 72 +++ .../RadixSort.cpp | 78 +++ String Algorithms/Aho-Corasick.cpp | 137 +++++ String Algorithms/Hashing.cpp | 90 ++++ String Algorithms/ManacherPalindromes.cpp | 84 +++ String Algorithms/PalindromeTree.cpp | 107 ++++ String Algorithms/PrefixFunction.cpp | 56 ++ String Algorithms/SuffixArray.cpp | 153 ++++++ String Algorithms/Trie.cpp | 61 +++ String Algorithms/UkkonenSuffixTree.cpp | 182 +++++++ String Algorithms/ZFunction.cpp | 62 +++ 31 files changed, 3417 insertions(+) create mode 100644 Computational Geometry/ClosestPairOfPoints.cpp create mode 100644 Computational Geometry/ClosestPairOfPointsNurlan.cpp create mode 100644 Data Structures/CartesianTree.cpp create mode 100644 Data Structures/CartesianTreeImplicitKeys.cpp create mode 100644 Data Structures/FenwickTree.cpp create mode 100644 Data Structures/FenwickTree2D.cpp create mode 100644 Data Structures/ImplicitSegmentTree.cpp create mode 100644 Data Structures/QueueWithMinimum.cpp create mode 100644 Data Structures/SegmentTree(Assign-Sum).cpp create mode 100644 Data Structures/SegmentTree.cpp create mode 100644 Data Structures/SparseTable.cpp create mode 100644 Dynamic Programming/LIS.cpp create mode 100644 Number Theory/BigInt.cpp create mode 100644 Number Theory/CatalanNumbers.cpp create mode 100644 Number Theory/DiophantineEquation.cpp create mode 100644 Number Theory/FFT.cpp create mode 100644 Number Theory/Gauss.cpp create mode 100644 Number Theory/NumberByPermutation.cpp create mode 100644 Number Theory/PermutationByNumber.cpp create mode 100644 Search and Randomized Algorithms/MergeSort.cpp create mode 100644 Search and Randomized Algorithms/QuickSort.cpp create mode 100644 Search and Randomized Algorithms/RadixSort.cpp create mode 100644 String Algorithms/Aho-Corasick.cpp create mode 100644 String Algorithms/Hashing.cpp create mode 100644 String Algorithms/ManacherPalindromes.cpp create mode 100644 String Algorithms/PalindromeTree.cpp create mode 100644 String Algorithms/PrefixFunction.cpp create mode 100644 String Algorithms/SuffixArray.cpp create mode 100644 String Algorithms/Trie.cpp create mode 100644 String Algorithms/UkkonenSuffixTree.cpp create mode 100644 String Algorithms/ZFunction.cpp diff --git a/Computational Geometry/ClosestPairOfPoints.cpp b/Computational Geometry/ClosestPairOfPoints.cpp new file mode 100644 index 0000000..bcaba8e --- /dev/null +++ b/Computational Geometry/ClosestPairOfPoints.cpp @@ -0,0 +1,125 @@ +/********************************************************************************** + + Finding the closest pair of points. O(NlogN), divide-and-conquer. + Based on http://www.spoj.com/problems/CLOPPAIR/ + +**********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define sqr(x) ((x) * (x)) + +const double inf = 1e100; +const int MAXN = 105000; + +struct point { + double x, y; + int ind; +}; + +bool cmp(point a, point b) { + return (a.x < b.x || (a.x == b.x && a.y < b.y)); +} + +double dist(point a, point b) { + return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)); +} + +int n; +int a[MAXN]; +point p[MAXN], tmp[MAXN]; +double ans = inf; +int p1, p2; + +void updateAnswer(point a, point b) { + double d = dist(a, b); + if (d < ans) { + ans = d; + p1 = a.ind; p2 = b.ind; + } +} + +void closestPair(int l, int r) { + if (l >= r) + return; + + if (r - l == 1) { + if (p[l].y > p[r].y) + swap(p[l], p[r]); + updateAnswer(p[l], p[r]); + return; + } + + int m = (l + r) / 2; + double mx = p[m].x; + + closestPair(l, m); + closestPair(m + 1, r); + + int lp = l, rp = m + 1, sz = 1; + while (lp <= m || rp <= r) { + if (lp > m || ((rp <= r && p[rp].y < p[lp].y))) { + tmp[sz] = p[rp]; + rp++; + } + else { + tmp[sz] = p[lp]; + lp++; + } + sz++; + } + + for (int i = l; i <= r; i++) + p[i] = tmp[i - l + 1]; + + sz = 0; + for (int i = l; i <= r; i++) + if (abs(p[i].x - mx) < ans) { + sz++; + tmp[sz] = p[i]; + } + + for (int i = 1; i <= sz; i++) { + for (int j = i - 1; j >= 1; j--) { + if (tmp[i].y - tmp[j].y >= ans) + break; + updateAnswer(tmp[i], tmp[j]); + } + } +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) { + scanf("%lf %lf", &p[i].x, &p[i].y); + p[i].ind = i - 1; + } + + sort(p + 1, p + n + 1, cmp); + + closestPair(1, n); + + printf("%d %d %.6lf\n", min(p1, p2), max(p1, p2), ans); + + return 0; +} \ No newline at end of file diff --git a/Computational Geometry/ClosestPairOfPointsNurlan.cpp b/Computational Geometry/ClosestPairOfPointsNurlan.cpp new file mode 100644 index 0000000..72b1d35 --- /dev/null +++ b/Computational Geometry/ClosestPairOfPointsNurlan.cpp @@ -0,0 +1,94 @@ +/*********** + +Solution to Closest Pair of Points Problem. O(nlogn) Divide-and-Conquer. +Tested on http://www.spoj.com/problems/CLOPPAIR/ + +***********/ +#include +#include +#include +#include +#include + +using namespace std; + +#define sqr(a) ((a)*(a)) +const double inf = 1e100; +const int MAXN = 55000; + + +struct point { + double x, y; + int ind; + void read() { + scanf("%lf%lf", &x, &y); + } + double dist_to(point& r) { + return sqrt(sqr(x - r.x) + sqr(y - r.y)); + } + bool operator<(const point&r) const { + return x < r.x || (x == r.x && y < r.y); + } +}; + +point aux[MAXN], P[MAXN], v[MAXN]; int vn; + +int a, b, n; +double ans = inf; + +// ans contains closest distance, a, b - indices of points. +void closest_pair(point p[], int n) { + if (n <= 1) return ; + if (n == 2) { + if (p[0].y > p[1].y) + swap(p[0], p[1]); + double d = p[0].dist_to(p[1]); + if (d < ans) + ans = d, a = p[0].ind, b = p[1].ind; + return; + } + int m = n / 2; + double x = p[m].x; + closest_pair(p, m); // left + closest_pair(p + m, n - m); //right + + int il = 0, ir = m, i = 0; + while (il < m && ir < n) { // merging two halves + if (p[il].y < p[ir].y) aux[i ++] = p[il ++]; + else aux[i ++] = p[ir ++]; + } + while (il < m) + aux[i ++] = p[il ++]; + while (ir < n) + aux[i ++] = p[ir ++]; + + vn = 0; + for (int j = 0 ; j < n ; j ++) { // copying back into p + p[j] = aux[j]; + if (fabs(p[j].x - x) < ans) // looking at the strip of width 2*ans + v[vn ++] = p[j]; + } + + for (int j = 0 ; j < vn ; j ++) { // (2*ans) x (ans) box + for (int k = j + 1 ; k < vn && v[k].y - v[j].y < ans ; k ++) { + double d = v[j].dist_to(v[k]); + if (ans > d) { + ans = d; + a = v[k].ind, b = v[j].ind; + } + } + } +} + +int main() { + scanf("%d", &n); + for (int i = 0 ; i < n ; i++) { + P[i].read(); + P[i].ind = i; + } + sort(P, P + n); + closest_pair(P, n); + printf("%d %d %lf\n", min(a, b), max(a, b), ans); + return 0; +} + diff --git a/Data Structures/CartesianTree.cpp b/Data Structures/CartesianTree.cpp new file mode 100644 index 0000000..c3fa068 --- /dev/null +++ b/Data Structures/CartesianTree.cpp @@ -0,0 +1,123 @@ +/************************************************************************************* + + Cartesian tree. Can be used as a balanced binary search tree. + O(logN) on operation. + + Based on problem 2782 from informatics.mccme.ru: + http://informatics.mccme.ru/mod/statements/view3.php?chapterid=2782 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int mod = 1000 * 1000 * 1000; + +struct node { + int x, y; + node *l, *r; + node(int new_x, int new_y) { + x = new_x; y = new_y; + l = NULL; r = NULL; + } +}; + +typedef node * pnode; + +void merge(pnode &t, pnode l, pnode r) { + if (l == NULL) + t = r; + else if (r == NULL) + t = l; + else if (l->y > r->y) { + merge(l->r, l->r, r); + t = l; + } + else { + merge(r->l, l, r->l); + t = r; + } +} + +void split(pnode t, int x, pnode &l, pnode &r) { + if (t == NULL) + l = r = NULL; + else if (t->x > x) { + split(t->l, x, l, t->l); + r = t; + } + else { + split(t->r, x, t->r, r); + l = t; + } +} + +void add(pnode &t, pnode a) { + if (t == NULL) + t = a; + else if (a->y > t->y) { + split(t, a->x, a->l, a->r); + t = a; + } + else { + if (t->x < a->x) + add(t->r, a); + else + add(t->l, a); + } +} + +int next(pnode t, int x) { + int ans = -1; + while (t != NULL) { + if (t->x < x) + t = t->r; + else { + if (ans == -1 || ans > t->x) + ans = t->x; + t = t->l; + } + } + return ans; +} + +int n, ans, x; +char qt, prev_qt; +pnode root = NULL, num; + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + + scanf("%d\n", &n); + for (int i = 1; i <= n; i++) { + scanf("%c %d\n", &qt, &x); + if (qt == '+') { + if (prev_qt == '?') + x = (x + ans) % mod; + num = new node(x, rand()); + add(root, num); + } + else { + ans = next(root, x); + printf("%d\n", ans); + } + prev_qt = qt; + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/CartesianTreeImplicitKeys.cpp b/Data Structures/CartesianTreeImplicitKeys.cpp new file mode 100644 index 0000000..827d734 --- /dev/null +++ b/Data Structures/CartesianTreeImplicitKeys.cpp @@ -0,0 +1,158 @@ +/************************************************************************************* + + Cartesian tree using implicit keys. Implementation below contains + array segment reverse and finding range minimum. O(logN) on operation. + + Based on problem 111240 from informatics.mccme.ru: + http://informatics.mccme.ru/mod/statements/view3.php?chapterid=111240 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int INF = 2 * 1000 * 1000 * 1000; + +struct node { + int y, val; + int sz, mn; + bool rev; + node *l, *r; + node (int new_val, int new_y) { + y = new_y; val = new_val; + sz = 1; mn = val; + rev = false; + l = NULL; r = NULL; + } +}; + +typedef node * pnode; + +int getsize(pnode t) { + if (t == NULL) + return 0; + return t->sz; +} + +int getmin(pnode t) { + if (t == NULL) + return INF; + return t->mn; +} + +void update(pnode t) { + if (t == NULL) + return; + t->sz = getsize(t->l) + 1 + getsize(t->r); + t->mn = min(t->val, min(getmin(t->r), getmin(t->l))); +} + +void push(pnode t) { + if (t && t->rev) { + swap(t->l, t->r); + if (t->l) + t->l->rev ^= true; + if (t->r) + t->r->rev ^= true; + t->rev = false; + } +} + +void merge(pnode &t, pnode l, pnode r) { + push(l); push(r); + if (l == NULL) + t = r; + else if (r == NULL) + t = l; + else if (l->y > r->y) { + merge(l->r, l->r, r); + t = l; + } + else { + merge(r->l, l, r->l); + t = r; + } + update(t); +} + +void split(pnode t, pnode &l, pnode &r, int x, int add = 0) { + push(t); + if (t == NULL) { + l = r = NULL; + return; + } + int key = getsize(t->l) + 1 + add; + if (x <= key) { + split(t->l, l, t->l, x, add); + r = t; + } + else { + split(t->r, t->r, r, x, add + getsize(t->l) + 1); + l = t; + } + update(t); +} + +void reverse(pnode t, int l, int r) { + pnode a, b; + split(t, t, a, l, 0); + split(a, a, b, r - l + 2, 0); + a->rev ^= true; + merge(t, t, a); + merge(t, t, b); +} + +int getmin(pnode t, int l, int r) { + int ans; + pnode a, b; + split(t, t, a, l, 0); + split(a, a, b, r - l + 2, 0); + ans = getmin(a); + merge(t, t, a); + merge(t, t, b); + return ans; +} + +int n, m; +int qt, l, r; +pnode root = NULL, add; + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + + scanf("%d %d\n", &n, &m); + for (int i = 1; i <= n; i++) { + int x; + scanf("%d", &x); + add = new node(x, rand()); + merge(root, root, add); + } + + for (int i = 1; i <= m; i++) { + scanf("%d %d %d",&qt, &l, &r); + if (qt == 1) { + reverse(root, l, r); + } + else { + printf("%d\n", getmin(root, l, r)); + } + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/FenwickTree.cpp b/Data Structures/FenwickTree.cpp new file mode 100644 index 0000000..10752fa --- /dev/null +++ b/Data Structures/FenwickTree.cpp @@ -0,0 +1,78 @@ +/************************************************************************************* + + Fenwick tree for sum on the interval and update of an element. + O(logN) on operation. + + Based on problem 3317 from informatics.mccme.ru: + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=3317#1 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +int n, m; +int a[MAXN]; +long long f[MAXN]; +char q; +int l, r; + +void update(int pos, int delta) { + for (; pos <= n; pos = (pos | (pos + 1))) + f[pos] += delta; +} + +long long sum(int pos) { + long long res = 0; + for (; pos > 0; pos = (pos & (pos + 1)) - 1) + res += f[pos]; + return res; +} + +long long sum(int l, int r) { + return sum(r) - sum(l - 1); +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) { + scanf("%d", &a[i]); + update(i, a[i]); + } + + scanf("%d\n", &m); + for (int i = 1; i <= m; i++) { + scanf("%c %d %d\n", &q, &l, &r); + if (q == 's') { + cout << sum(l, r) << " "; + } + else { + int delta = r - a[l]; + a[l] = r; + update(l, delta); + } + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/FenwickTree2D.cpp b/Data Structures/FenwickTree2D.cpp new file mode 100644 index 0000000..38d53b7 --- /dev/null +++ b/Data Structures/FenwickTree2D.cpp @@ -0,0 +1,81 @@ +/************************************************************************************* + + Fenwick tree for sum on the rectangle and update of an element. + O(logN ^ 2) on query. + + Based on problem 3013 from informatics.mccme.ru: + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=3013#1 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1050; + +int n, m; +int qn; +char q[10]; +int f[MAXN][MAXN]; + +void update(int x, int y, int delta) { + for (int i = x; i <= n; i = i | (i + 1)) + for (int j = y; j <= m; j = j | (j + 1)) + f[i][j] += delta; +} + +int getSum(int x, int y) { + int res = 0; + for (int i = x; i > 0; i = (i & (i + 1)) - 1) + for (int j = y; j > 0; j = (j & (j + 1)) - 1) + res += f[i][j]; + return res; +} + +int getSum(int xFrom, int xTo, int yFrom, int yTo) { + return getSum(xTo, yTo) - getSum(xTo, yFrom - 1) - getSum(xFrom - 1, yTo) + getSum(xFrom - 1, yFrom - 1); +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d\n", &n, &qn); + m = n; + + for (int i = 1; i <= qn; i++) { + scanf("%s", &q); + if (q[0] == 'A') { + int x, y; + scanf("%d %d\n", &x, &y); + update(x, y, 1); + } + else { + int xFrom, xTo, yFrom, yTo; + scanf("%d %d %d %d\n", &xFrom, &yFrom, &xTo, &yTo); + if (xFrom > xTo) + swap(xFrom, xTo); + if (yFrom > yTo) + swap(yFrom, yTo); + printf("%d\n", getSum(xFrom, xTo, yFrom, yTo)); + } + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/ImplicitSegmentTree.cpp b/Data Structures/ImplicitSegmentTree.cpp new file mode 100644 index 0000000..7ec7cf8 --- /dev/null +++ b/Data Structures/ImplicitSegmentTree.cpp @@ -0,0 +1,97 @@ +/************************************************************************************* + + Implicit segment tree with addition on the interval + and getting the value of some element. + + Works on the intervals like [1..10^9]. + O(logN) on query, O(NlogN) of memory. + + Author: Bekzhan Kassenov. + + Based on problem 3327 from informatics.mccme.ru + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=3327 + +*************************************************************************************/ + +#include +#include +#include + +using namespace std; + +typedef long long ll; + +struct Node { + ll sum; + Node *l, *r; + + Node() : sum(0), l(NULL), r(NULL) { } +}; + +void add(Node *v, int l, int r, int q_l, int q_r, ll val) { + if (l > r || q_r < l || q_l > r) + return; + + if (q_l <= l && r <= q_r) { + v -> sum += val; + return; + } + + int mid = (l + r) >> 1; + + if (v -> l == NULL) + v -> l = new Node(); + + if (v -> r == NULL) + v -> r = new Node(); + + add(v -> l, l, mid, q_l, q_r, val); + add(v -> r, mid + 1, r, q_l, q_r, val); +} + +ll get(Node *v, int l, int r, int pos) { + if (!v || l > r || pos < l || pos > r) + return 0; + + if (l == r) + return v -> sum; + + int mid = (l + r) >> 1; + + return v -> sum + get(v -> l, l, mid, pos) + get(v -> r, mid + 1, r, pos); +} + +int n, m, t, x, y, val; +char c; + +int main() { + //freopen("input.txt", "r", stdin); + //freopen("output.txt", "w", stdout); + + Node *root = new Node(); + + scanf("%d", &n); + + for (int i = 0; i < n; i++) { + scanf("%d", &x); + add(root, 0, n - 1, i, i, x); + } + + scanf("%d", &m); + + for (int i = 0; i < m; i++) { + scanf("\n%c", &c); + + if (c == 'a') { + scanf("%d%d%d", &x, &y, &val); + + add(root, 0, n - 1, --x, --y, val); + } else { + scanf("%d", &x); + + printf("%I64d ", get(root, 0, n - 1, --x)); + } + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/QueueWithMinimum.cpp b/Data Structures/QueueWithMinimum.cpp new file mode 100644 index 0000000..6a51974 --- /dev/null +++ b/Data Structures/QueueWithMinimum.cpp @@ -0,0 +1,80 @@ +/************************************************************************************* + + Modification of queue, which allows finding the minimum element in it. + Time complexity: O(1) on operation. + + Based on problem 756 from informatics.mccme.ru: + http://informatics.mccme.ru//mod/statements/view.php?chapterid=756#1 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 205000; + +int n, m; +deque < pair > d; +int a[MAXN]; + +void enqueue(int x) { + int num = 1; + while (!d.empty() && d.back().first > x) { + num += d.back().second; + d.pop_back(); + } + d.push_back(make_pair(x, num)); +} + +void dequeue() { + if (d.front().second == 1) { + d.pop_front(); + } + else { + d.front().second--; + } +} + +int getMin() { + return d.front().first; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &m); + + for (int i = 1; i <= n; i++) + scanf("%d", &a[i]); + + for (int i = 1; i <= m; i++) { + enqueue(a[i]); + } + + printf("%d\n", getMin()); + + for (int i = m + 1; i <= n; i++) { + dequeue(); + enqueue(a[i]); + printf("%d\n", getMin()); + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/SegmentTree(Assign-Sum).cpp b/Data Structures/SegmentTree(Assign-Sum).cpp new file mode 100644 index 0000000..1162993 --- /dev/null +++ b/Data Structures/SegmentTree(Assign-Sum).cpp @@ -0,0 +1,120 @@ +/********************************************************************** + + Segment Tree with assignment and sum on the interval + + Based on problem C from http://codeforces.ru/gym/100093 + +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; +const int zero = -1; + +struct node { + long long sum; + int val; + int size; +}; + +int n, m; +char qt; +int x, l, r; +int a[MAXN]; +vector tree; + +void build (int v, int L, int R, int a[]) { + if (L == R) { + tree[v].sum = tree[v].val = a[L]; + tree[v].size = 1; + } + else { + int mid = L + (R - L) / 2; + build(2 * v, L, mid, a); + build(2 * v + 1, mid + 1, R, a); + tree[v].sum = tree[2 * v].sum + tree[2 * v + 1].sum; + tree[v].val = zero; + tree[v].size = tree[2 * v + 1].size + tree[2 * v].size; + } +} + +void push(int v) { + if (tree[v].val == zero) + return; + if (tree[v].size != 1) { + tree[2 * v].val = tree[v].val; + tree[2 * v + 1].val = tree[v].val; + } + tree[v].sum = 1ll * tree[v].size * tree[v].val; + tree[v].val = zero; +} + +void assign(int v, int L, int R, int l, int r, int val) { + if (l > r) + return; + push(v); + if (L == l && R == r) { + tree[v].val = val; + tree[v].sum = 1ll * val * tree[v].size; + } else { + int mid = L + (R - L) / 2; + assign(2 * v, L, mid, l, min(mid, r), val); + assign(2 * v + 1, mid + 1, R, max(mid + 1, l), r, val); + push(2 * v); + push(2 * v + 1); + tree[v].sum = tree[2 * v].sum + tree[2 * v + 1].sum; + } + push(v); +} + +long long getsum(int v, int L, int R, int l, int r) { + if (l > r) + return 0; + push(v); + if (l == L && r == R) + return tree[v].sum; + int mid = L + (R - L) / 2; + long long res = getsum(2 * v, L, mid, l, min(mid, r)) + getsum(2 * v + 1, mid + 1, R, max(l, mid + 1), r); + return res; +} + +int main() { + assert(freopen("sum.in","r",stdin)); + assert(freopen("sum.out","w",stdout)); + + scanf("%d %d\n", &n, &m); + + tree.resize(4 * n); + build(1, 1, n, a); + + for (int i = 1; i <= m; i++) { + scanf("%c", &qt); + if (qt == 'A') { + scanf("%d %d %d\n", &l, &r, &x); + assign(1, 1, n, l, r, x); + } + else { + scanf("%d %d\n", &l, &r); + cout << getsum(1, 1, n, l, r) << endl; + } + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/SegmentTree.cpp b/Data Structures/SegmentTree.cpp new file mode 100644 index 0000000..0d926dc --- /dev/null +++ b/Data Structures/SegmentTree.cpp @@ -0,0 +1,97 @@ +/************************************************************************************* + + Segment tree. Solves RMQ problem (maximum on a segment and value update) + O(N) on precalculation, O(logN) on query. + + Based on problem 3309 from informatics.mccme.ru: + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=3309 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; +const int INF = (int) 1e9; + +int n, num, qn; +int a[MAXN]; +int tree[4 * MAXN]; +int l, r; + +int getMax(int l, int r) { + l = num + l - 1; r = num + r - 1; + int res = -INF; + + while (l <= r) { + if (l & 1) { + res = max(res, tree[l]); + l++; + } + if (r % 2 == 0) { + res = max(res, tree[r]); + r--; + } + l /= 2; r /= 2; + } + + return res; +} + +void update(int pos, int val) { + pos = num + pos - 1; + tree[pos] = val; + pos /= 2; + while (pos >= 1) { + tree[pos] = max(tree[pos * 2], tree[pos * 2 + 1]); + pos /= 2; + } +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + scanf("%d", &a[i]); + + num = 1; + while (num < n) + num *= 2; + + for (int i = num; i < 2 * num; i++) { + if (i - num + 1 <= n) + tree[i] = a[i - num + 1]; + else + tree[i] = -INF; + } + + for (int i = num - 1; i >= 1; i--) { + tree[i] = max(tree[i * 2], tree[i * 2 + 1]); + } + + scanf("%d", &qn); + for (int i = 1; i <= qn; i++) { + scanf("%d %d", &l, &r); + printf("%d ", getMax(l, r)); + } + + return 0; +} \ No newline at end of file diff --git a/Data Structures/SparseTable.cpp b/Data Structures/SparseTable.cpp new file mode 100644 index 0000000..2a8195c --- /dev/null +++ b/Data Structures/SparseTable.cpp @@ -0,0 +1,80 @@ +/************************************************************************************* + + Sparse table. Solves static RMQ problem (without element changes). + O(NlogN) on precalculation, O(1) on query. + + Based on problem 3309 from informatics.mccme.ru: + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=3309 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 2 * 105000; +const int MAXLOG = 20; + +int n, m; +int a[MAXN]; +int table[MAXLOG][MAXN]; +int numlog[MAXN]; + +void buildTable() { + numlog[1] = 0; + for (int i = 2; i <= n; i++) + numlog[i] = numlog[i / 2] + 1; + + for (int i = 0; i <= numlog[n]; i++) { + int curlen = 1 << i; + for (int j = 1; j <= n; j++) { + if (i == 0) { + table[i][j] = a[j]; + continue; + } + table[i][j] = max(table[i - 1][j], table[i - 1][j + curlen / 2]); + } + } +} + +int getMax(int l, int r) { + int curlog = numlog[r - l + 1]; + return max(table[curlog][l], table[curlog][r - (1 << curlog) + 1]); +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + + for (int i = 1; i <= n; i++) + scanf("%d", &a[i]); + + buildTable(); + + scanf("%d", &m); + + for (int i = 1; i <= m; i++) { + int l, r; + scanf("%d %d", &l, &r); + printf("%d ", getMax(l, r)); + } + + return 0; +} \ No newline at end of file diff --git a/Dynamic Programming/LIS.cpp b/Dynamic Programming/LIS.cpp new file mode 100644 index 0000000..2097b91 --- /dev/null +++ b/Dynamic Programming/LIS.cpp @@ -0,0 +1,80 @@ +/**************************************************************************************************** + + Finding Longest Increasing Sequence in O(NlogN) + About it: http://e-maxx.ru/algo/longest_increasing_subseq_log + Based on problem http://informatics.mccme.ru/mod/statements/view3.php?id=766&chapterid=1794 + +****************************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; +const int INF = 1000 * 1000 * 1000; + +int n; +int k, b, m; +int a[MAXN]; +int d[MAXN]; +int ind[MAXN], pr[MAXN]; +vector ansv; +int ans = 1; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + scanf("%d %d %d %d", &a[1], &k, &b, &m); + + for (int i = 2; i <= n; i++) + a[i] = (k * a[i - 1] + b) % m; + + d[0] = -INF; + for (int i = 1; i <= n; i++) + d[i] = INF; + + for (int i = 1; i <= n; i++) { + int pos = upper_bound(d + 1, d + n + 1, a[i]) - d; + if (d[pos - 1] < a[i] && a[i] < d[pos]) { + d[pos] = a[i]; + ind[pos] = i; + pr[i] = ind[pos - 1]; + if (pos > ans) { + ans = pos; + } + } + } + + if (ans == 1) { + printf("%d", a[1]); + } + else { + int cur = ind[ans]; + while (cur != 0) { + ansv.push_back(a[cur]); + cur = pr[cur]; + } + + for (int i = (int) ansv.size() - 1; i >= 0; i--) + printf("%d ", ansv[i]); + } + + return 0; +} \ No newline at end of file diff --git a/Number Theory/BigInt.cpp b/Number Theory/BigInt.cpp new file mode 100644 index 0000000..b398122 --- /dev/null +++ b/Number Theory/BigInt.cpp @@ -0,0 +1,489 @@ +/******************************************************************************** + + Structure implementing long arithmetic in C++ + Analogue to BigInteger in Java. + Tested on many problems. + + TODO: list some problems + +********************************************************************************/ + +struct BigInt { + + vector num; + + static const int base = 1000 * 1000 * 1000; + static const int baseDigits = 9; + string leadingZerosModifier; + + /**************************************************** + * CONSTRUCTONS & SETTERS + ****************************************************/ + + void setLeadingZerosModifier() { + leadingZerosModifier = "%0xd"; + leadingZerosModifier[2] = '0' + baseDigits; + } + + void set(int value) { + num.clear(); + if (value == 0) + num.push_back(0); + while (value) { + num.push_back(value % base); + value /= base; + } + } + + void set(long long value) { + num.clear(); + if (value == 0) + num.push_back(0); + while (value) { + num.push_back(value % base); + value /= base; + } + } + + void set(string &value) { + num.clear(); + for (int i = (int)value.length() - 1; i >= 0; i -= baseDigits) { + int add = 0; + for (int j = max(0, i - baseDigits + 1); j <= i; j++) + add = add * 10 + value[j] - '0'; + num.push_back(add); + } + } + + void operator = (int value) { + set(value); + } + + void operator = (long long value) { + set(value); + } + + void operator = (string &value) { + set(value); + } + + BigInt() { + setLeadingZerosModifier(); + set(0); + } + + BigInt(int value) { + setLeadingZerosModifier(); + set(value); + } + + BigInt(string value) { + setLeadingZerosModifier(); + set(value); + } + + /*==================================================== + * SIZE METHODS + ====================================================*/ + + //returns size of vector + int size() { + return (int)num.size(); + } + + //returns length of the number + int digitNum() { + int result = 0; + for (int i = 0; i < (int)num.size() - 1; i++) + result += baseDigits; + int lastNum = num.back(); + while (lastNum) { + result++; + lastNum /= 10; + } + return result; + } + + /*==================================================== + * I/O + ====================================================*/ + + void read() { + string s; + cin >> s; + num.clear(); + for (int i = (int)s.length() - 1; i >= 0; i -= baseDigits) { + int add = 0; + for (int j = max(0, i - baseDigits + 1); j <= i; j++) + add = add * 10 + s[j] - '0'; + num.push_back(add); + } + } + + void print() { + printf("%d", num.back()); + for (int i = (int)num.size() - 2; i >= 0; i--) + printf (leadingZerosModifier.c_str(), num[i]); + } + + void println() { + print(); + printf("\n"); + } + + string toString() { + string result = ""; + for (int i = 0; i < (int)num.size(); i++) { + int cur = num[i]; + for (int j = 1; j <= baseDigits; j++) { + if (cur == 0 && i == (int) num.size() - 1) + break; + result.append(1, (char) '0' + cur % 10); + cur /= 10; + } + } + reverse(result.begin(), result.end()); + return result; + } + + /*==================================================== + * ADDITION + ====================================================*/ + + void sumThis(BigInt number) { + int carry = 0; + for (int i = 0; i < max((int)num.size(), number.size()) || carry; i++) { + if (i == num.size()) + num.push_back(0); + if (i >= number.size()) + carry = num[i] + carry; + else + carry = num[i] + carry + number.num[i]; + num[i] = carry % base; + carry /= base; + } + } + + void sumThis(int number) { + int carry = number; + for (int i = 0; i < (int)num.size() || carry; i++) { + if (i == num.size()) + num.push_back(0); + carry = num[i] + carry; + num[i] = carry % base; + carry /= base; + } + } + + BigInt sum(BigInt number) { + BigInt result = *this; + result.sumThis(number); + return result; + } + + BigInt sum(int number) { + BigInt result = *this; + result.sumThis(number); + return result; + } + + void operator += (BigInt number) { + sumThis(number); + } + + void operator += (int number) { + sumThis(number); + } + + BigInt operator + (BigInt number) { + return sum(number); + } + + BigInt operator + (int number) { + return sum(number); + } + + /*==================================================== + * SUBTRACTION + ====================================================*/ + + void subThis(BigInt number) { + int carry = 0; + for (int i = 0; i < (int)number.size() || carry; i++) { + if (i < (int)number.size()) + num[i] -= carry + number.num[i]; + else + num[i] -= carry; + if (num[i] < 0) { + carry = 1; + num[i] += base; + } + else + carry = 0; + } + while (num.size() > 1 && num.back() == 0) + num.pop_back(); + } + + void subThis(int number) { + int carry = -number; + for (int i = 0; carry > 0; i++) { + num[i] -= carry; + if (num[i] < 0) { + carry = 1; + num[i] += base; + } + else + carry = 0; + } + while (num.size() > 1 && num.back() == 0) + num.pop_back(); + } + + BigInt sub(BigInt number) { + BigInt result = *this; + result.subThis(number); + return result; + } + + BigInt sub(int number) { + BigInt result = *this; + result.subThis(number); + return result; + } + + void operator -= (BigInt number) { + subThis(number); + } + + void operator -= (int number) { + subThis(number); + } + + BigInt operator - (BigInt number) { + return sub(number); + } + + BigInt operator - (int number) { + return sub(number); + } + + /*==================================================== + * MULTIPLICATION + ====================================================*/ + + BigInt mult(BigInt number) { + BigInt product; + product.num.resize(num.size() + number.size()); + for (int i = 0; i < (int)num.size(); i++) { + for (int j = 0, carry = 0; j < (int)number.size() || carry; j++) { + long long cur = product.num[i + j] + num[i] * 1ll * (j < (int)number.size() ? number.num[j] : 0) + carry; + product.num[i + j] = int (cur % base); + carry = int (cur / base); + } + } + while (product.size() > 1 && product.num.back() == 0) + product.num.pop_back(); + return product; + } + + void multThis(BigInt number) { + *this = mult(number); + } + + void multThis(int number) { + int carry = 0; + for (int i = 0; i < (int)num.size() || carry; ++i) { + if (i == num.size()) + num.push_back (0); + long long cur = carry + num[i] * 1ll * number; + num[i] = int (cur % base); + carry = int (cur / base); + } + while (num.size() > 1 && num.back() == 0) + num.pop_back(); + } + + BigInt mult(int number) { + BigInt result = *this; + result.multThis(number); + return result; + } + + void operator *= (BigInt number) { + multThis(number); + } + + void operator *= (int number) { + multThis(number); + } + + BigInt operator * (BigInt number) { + return mult(number); + } + + BigInt operator * (int number) { + return mult(number); + } + + void multThisByPowerOfTen(int power) { + int baseNums = power / baseDigits; + int curLen = (int)num.size(); + num.resize(curLen + baseNums); + for (int i = num.size() - 1; i >= baseNums; i--) { + num[i] = num[i - baseNums]; + } + for (int i = baseNums - 1; i >= 0; i--) + num[i] = 0; + power %= baseDigits; + int multBy = (int)pow(10.0, power); + multThis(multBy); + } + + /*==================================================== + * DIVISION + ====================================================*/ + + void divThis(int number) { + int carry = 0; + for (int i= (int)num.size() - 1; i >= 0; i--) { + long long cur = num[i] + carry * 1ll * base; + num[i] = int (cur / number); + carry = int (cur % number); + } + while (num.size() > 1 && num.back() == 0) + num.pop_back(); + } + + BigInt div(int number) { + BigInt result = *this; + result.divThis(number); + return result; + } + + void operator /= (int number) { + divThis(number); + } + + BigInt operator / (int number) { + return div(number); + } + + void divThisByPowerOfTen(int power) { + int baseNums = power / baseDigits; + int curLen = (int)num.size(); + for (int i = 0; i < (int)num.size() - baseNums; i++) { + num[i] = num[i + baseNums]; + } + for (int i = 1; i <= baseNums; i++) + num.pop_back(); + power %= baseDigits; + int divBy = (int)pow(10.0, power); + divThis(divBy); + } + + /*==================================================== + * MODULO + ====================================================*/ + + void modThis(int number) { + int carry = 0; + for (int i= (int)num.size() - 1; i >= 0; i--) { + long long cur = num[i] + carry * 1ll * base; + num[i] = int (cur / number); + carry = int (cur % number); + } + set(carry); + } + + BigInt mod(int number) { + BigInt result = *this; + result.modThis(number); + return result; + } + + void operator %= (int number) { + modThis(number); + } + + BigInt operator % (int number) { + return mod(number); + } + + /*==================================================== + * COMPARISON + ====================================================*/ + + //Returns: -1 - this number is less than argument, 0 - equal, 1 - this number is greater + int compareTo(BigInt number) { + if ((int)num.size() < number.size()) + return -1; + if ((int)num.size() > number.size()) + return 1; + for (int i = (int)num.size() - 1; i >= 0; i--) { + if (num[i] > number.num[i]) + return 1; + if (num[i] < number.num[i]) + return -1; + } + return 0; + } + + //Returns: -1 - this number is less than argument, 0 - equal, 1 - this number is greater + int compareTo(int number) { + if (num.size() > 1 || num[0] > number) + return 1; + if (num[0] < number) + return -1; + return 0; + } + + bool operator < (BigInt number) { + return compareTo(number) == -1; + } + + bool operator < (int number) { + return compareTo(number) == -1; + } + + bool operator <= (BigInt number) { + return compareTo(number) != 1; + } + + bool operator <= (int number) { + return compareTo(number) != 1; + } + + bool operator == (BigInt number) { + return compareTo(number) == 0; + } + + bool operator == (int number) { + return compareTo(number) == 0; + } + + bool operator > (BigInt number) { + return compareTo(number) == 1; + } + + bool operator > (int number) { + return compareTo(number) == 1; + } + + bool operator >= (BigInt number) { + return compareTo(number) != -1; + } + + bool operator >= (int number) { + return compareTo(number) != 1; + } + + bool operator != (BigInt number) { + return compareTo(number) != 0; + } + + bool operator != (int number) { + return compareTo(number) != 0; + } + +}; \ No newline at end of file diff --git a/Number Theory/CatalanNumbers.cpp b/Number Theory/CatalanNumbers.cpp new file mode 100644 index 0000000..1b0ab90 --- /dev/null +++ b/Number Theory/CatalanNumbers.cpp @@ -0,0 +1,81 @@ +/******************************************************************************* + + Finding Nth Catalan number modulo some mod + (N <= 500000, mod is not necessary prime) + + Uses Eratosthenes sieve for fast factorization + Works in O(N * loglogN) + + Based on problem 140 from acm.mipt.ru + http://acm.mipt.ru/judge/problems.pl?problem=140 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 500500; + +int n, mod; +int sieve[2 * MAXN]; +int p[2 * MAXN]; +long long ans = 1; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &mod); + + for (int i = 2; i <= 2 * n; i++) { + if (sieve[i] == 0) { + for (int j = 2 * i; j <= 2 * n; j += i) { + if (sieve[j] == 0) + sieve[j] = i; + } + } + } + + for (int i = n + 2; i <= 2 * n; i++) { + int x = i; + while (sieve[x] != 0) { + p[sieve[x]]++; + x /= sieve[x]; + } + p[x]++; + } + + for (int i = 1; i <= n; i++) { + int x = i; + while (sieve[x] != 0) { + p[sieve[x]]--; + x /= sieve[x]; + } + p[x]--; + } + + for (int i = 2; i <= 2 * n; i++) { + for (int j = 1; j <= p[i]; j++) + ans = (1ll * ans * i) % mod; + } + + cout << ans % mod << endl; + + return 0; +} \ No newline at end of file diff --git a/Number Theory/DiophantineEquation.cpp b/Number Theory/DiophantineEquation.cpp new file mode 100644 index 0000000..353b71b --- /dev/null +++ b/Number Theory/DiophantineEquation.cpp @@ -0,0 +1,97 @@ +/************************************************************************************ + + Solving Diophantine equations in form of a * x + b * y = c + + Uses extended Euclid algorithm + (which finds such x, y that a * x + b * y = gcd(a, b)) + + Based on problem 4188 from informatics.mccme.ru + http://informatics.mccme.ru/moodle/mod/statements/view3.php?chapterid=4188 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +long long gcd(long long a, long long b) { + if (b == 0) + return a; + return gcd(b, a % b); +} + +// Finds such x and y, that a * x + b * y = gcd(a, b) +long long extended_gcd(long long a, long long b, long long &x, long long &y) { + if (b == 0) { + x = 1; y = 0; + return a; + } + long long x1, y1; + long long g = extended_gcd(b, a % b, x1, y1); + x = y1; + y = x1 - (a / b) * y1; + return g; +} + +// Solves equation a * x + b * y = c, writes answer to x and y +void solveDiophantine(long long a, long long b, long long c, long long &x, long long &y) { + long long g = extended_gcd(a, b, x, y); + + if (c % g != 0) { + puts("Impossible"); + exit(0); + } + + c /= g; + + x = x * c; y = y * c; +} + +long long a, b, c; +long long x, y; +long long g; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + cin >> a >> b >> c; + + // Find any solution + solveDiophantine(a, b, c, x, y); + + // In this problem we search for solution with minimum x >= 0 + // a * x + b * y = gcd(a, b) + // now for any integer k: a * (x + k * b / g) + b * (y - k * a / g) = gcd(a, b) + + g = gcd(a, b); + + long long add = b / g; + long long num = 0; + if (add < 0) + num = (long long) floor(1.0 * -x / add); + else + num = (long long) ceil(1.0 * -x / add); + + x = x + b / g * num; + y = y - a / g * num; + + cout << x << " " << y; + + return 0; +} \ No newline at end of file diff --git a/Number Theory/FFT.cpp b/Number Theory/FFT.cpp new file mode 100644 index 0000000..1edb4d4 --- /dev/null +++ b/Number Theory/FFT.cpp @@ -0,0 +1,126 @@ +/******************************************************************************** + + Fast Fourier transformation used to multiply long numbers. + Fast non-recursive version. O(NlogN). + Based on problem 317 from E-Olimp: http://www.e-olimp.com.ua/problems/317 + +********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +typedef complex comp; +const double pi = acos(-1.0); +const int MAXN = 505000; + +int rev[MAXN * 2]; + +void fft( comp p[], int n, bool invert) { + int dig = 0; + while ((1 << dig) < n) + dig++; + + for (int i = 0; i < n; i++) { + rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (dig - 1)); + if (rev[i] > i) + swap(p[i], p[rev[i]]); + } + + for (int len = 2; len <= n; len <<= 1) { + double angle = 2 * pi / len; + if (invert) + angle *= -1; + comp wgo(cos(angle), sin(angle)); + for (int i = 0; i < n; i += len) { + comp w(1); + for (int j = 0; j < (len >> 1); j++) { + comp a = p[i + j], b = w * p[i + j + (len >> 1)]; + p[i + j] = a + b; + p[i + j + (len >> 1)] = a - b; + w *= wgo; + } + } + } + if (invert) + for (int i = 0; i < n; i++) + p[i] /= n; +} + +comp a[MAXN * 2], b[MAXN * 2]; +int ans[MAXN * 2]; +int alen, blen, total; + +void readPolynom(comp p[], int &len, bool space) { + string s; + if (space) + getline(cin, s, ' '); + else + getline(cin, s); + len = 1; + while (len < (int) s.length()) + len *= 2; + + memset(p, 0, sizeof(p)); + + int pos = 0; + for (int i = (int) s.length() - 1; i >= 0; i--) { + comp coeff(s[i] - '0'); + p[pos] = coeff; + pos++; + } +} + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + readPolynom(a, alen, true); + readPolynom(b, blen, false); + + total = max(alen, blen); + total *= 2; + + fft(a, total, false); + fft(b, total, false); + + for (int i = 0; i < total; i++) + a[i] = a[i] * b[i]; + + fft(a, total, true); + + for (int i = 0; i < total; i++) + ans[i] = (int) floor(a[i].real() + 0.5); + + int go = 0; + for (int i = 0; i < total; i++) { + ans[i] += go; + go = ans[i] / 10; + ans[i] %= 10; + } + + int ans_ind = total - 1; + while (ans_ind > 0 && ans[ans_ind] == 0) + ans_ind--; + + for (int i = ans_ind; i >= 0; i--) + printf("%d", ans[i]); + printf("\n"); + + return 0; +} \ No newline at end of file diff --git a/Number Theory/Gauss.cpp b/Number Theory/Gauss.cpp new file mode 100644 index 0000000..1c0cd65 --- /dev/null +++ b/Number Theory/Gauss.cpp @@ -0,0 +1,117 @@ +/******************************************************************************* + + Gauss method of solving system of linear algebraic equation. + Works in O(n ^ 3) (more precisely - O(min(n, m) * n * m)) + + Based on problem 198 from acmp.ru: + http://acmp.ru/index.asp?main=task&id_task=198 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 150; +const int INF = 1 << 20; +const double eps = 1e-6; + +int n, m; +double a[MAXN][MAXN]; +double ans[MAXN]; + +// returns the number of solutions: 0, 1 or infinity +// in case of any solution, it is written in the ans[] array +int gauss(int n, int m, double a[MAXN][MAXN], double ans[MAXN]) { + int pos[MAXN]; + memset(pos, 0, sizeof(pos)); + + bool parameters = false; + int row = 1, col = 1; + + for (; row <= n && col <= m; col++) { + int pivot = row; + for (int i = row; i <= n; i++) + if (abs(a[i][col]) > abs(a[pivot][col])) + pivot = i; + + if (abs(a[pivot][col]) < eps) { + parameters = true; + continue; + } + + for (int i = 1; i <= m + 1; i++) + swap(a[row][i], a[pivot][i]); + + pos[col] = row; + + double div = a[row][col]; + for (int i = 1; i <= m + 1; i++) + a[row][i] /= div; + + for (int i = 1; i <= n; i++) { + if (i == row) + continue; + div = a[i][col]; + for (int j = 1; j <= m + 1; j++) + a[i][j] -= a[row][j] * div; + } + + row++; + } + + for (int i = 1; i <= m; i++) + if (pos[i] != 0) + ans[i] = a[pos[i]][m + 1]; + else + ans[i] = 0; + + for (int i = 1; i <= n; i++) { + double sum = 0; + for (int j = 1; j <= m; j++) + sum += ans[j] * a[i][j]; + if (abs(sum - a[i][m + 1]) > eps) + return 0; + } + + if (parameters) + return INF; + + return 1; +} + +int main() { + freopen("input.txt","r",stdin); + freopen("output.txt","w",stdout); + + scanf("%d", &n); + m = n; + + for (int i = 1; i <= n; i++) + for (int j = 1; j <= m + 1; j++) + scanf("%lf", &a[i][j]); + + if (gauss(n, m, a, ans) == 1) { + for (int i = 1; i <= m; i++) { + ans[i] = floor(ans[i] + 0.5); + printf("%.0lf ", ans[i]); + } + } + + return 0; +} \ No newline at end of file diff --git a/Number Theory/NumberByPermutation.cpp b/Number Theory/NumberByPermutation.cpp new file mode 100644 index 0000000..141c365 --- /dev/null +++ b/Number Theory/NumberByPermutation.cpp @@ -0,0 +1,66 @@ +/******************************************************************************* + + Finding number of permutation in lexicographical order + Works in O(n^2) + + Based on problem 2388 from e-olimp.com + http://www.e-olimp.com/problems/2388 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 20; + +int n; +int f[MAXN]; +int p[MAXN]; +bool used[MAXN]; +int ans; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + scanf("%d", &p[i]); + + f[0] = 1; + for (int i = 1; i <= n; i++) + f[i] = f[i - 1] * i; + + ans = 1; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + if (used[j]) + continue; + if (p[i] == j) { + used[j] = true; + break; + } + ans += f[n - i]; + } + } + + printf("%d\n", ans); + + return 0; +} \ No newline at end of file diff --git a/Number Theory/PermutationByNumber.cpp b/Number Theory/PermutationByNumber.cpp new file mode 100644 index 0000000..17afd2d --- /dev/null +++ b/Number Theory/PermutationByNumber.cpp @@ -0,0 +1,73 @@ +/******************************************************************************* + + Finding permutation by its length and number in lexicographical order + Works in O(n^2) + + Based on problem 190 from informatics.mccme.ru + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=190#1 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 20; + +int n, num; +bool used[MAXN]; +int f[MAXN]; + +void permutationByNumber(int n, int num) { + for (int i = 1; i <= n; i++) + used[i] = false; + + int cur = 0; + + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + if (used[j]) + continue; + int add = f[n - i]; + if (cur + add >= num) { + used[j] = true; + printf("%d ", j); + break; + } + cur += add; + } + } + printf("\n"); +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + scanf("%d", &num); + + f[0] = 1; + for (int i = 1; i <= n; i++) { + f[i] = f[i - 1] * i; + } + + permutationByNumber(n, num); + + return 0; +} \ No newline at end of file diff --git a/Search and Randomized Algorithms/MergeSort.cpp b/Search and Randomized Algorithms/MergeSort.cpp new file mode 100644 index 0000000..7a52170 --- /dev/null +++ b/Search and Randomized Algorithms/MergeSort.cpp @@ -0,0 +1,73 @@ +/************************************************************************************ + + Merge sort. O(NlogN). + Based on problem 766 from informatics.mccme.ru: + http://informatics.mccme.ru/mod/statements/view3.php?id=1129&chapterid=766 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +int n; +int a[MAXN], tmp[MAXN]; + +void mergesort(int l, int r) { + if (l >= r) + return; + + int mid = (l + r) / 2; + + mergesort(l, mid); + mergesort(mid + 1, r); + + int p1 = l, p2 = mid + 1, cur = 1; + while (p1 <= mid || p2 <= r) { + if (p1 > mid || (p2 <= r && a[p2] < a[p1])) { + tmp[cur] = a[p2]; + p2++; + } + else { + tmp[cur] = a[p1]; + p1++; + } + cur++; + } + + for (int i = 1; i <= r - l + 1; i++) + a[l + i - 1] = tmp[i]; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + scanf("%d", &a[i]); + + mergesort(1, n); + + for (int i = 1; i <= n; i++) + printf("%d ", a[i]); + + return 0; +} \ No newline at end of file diff --git a/Search and Randomized Algorithms/QuickSort.cpp b/Search and Randomized Algorithms/QuickSort.cpp new file mode 100644 index 0000000..d7181ec --- /dev/null +++ b/Search and Randomized Algorithms/QuickSort.cpp @@ -0,0 +1,72 @@ +/************************************************************************************ + + Quick sort with random pivot element. O(NlogN). + Based on problem 766 from informatics.mccme.ru: + http://informatics.mccme.ru/mod/statements/view3.php?id=1129&chapterid=766 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +int n; +int a[MAXN]; + +void qsort(int l, int r) { + if (l >= r) + return; + + int pivot = l + rand() % (r - l); + int key = a[pivot]; + + int i = l, j = r; + while (i <= j) { + while (a[i] < key) + i++; + while (a[j] > key) + j--; + if (i <= j) { + swap(a[i], a[j]); + i++; j--; + } + } + + if (l < j) + qsort(l, j); + if (i < r) + qsort(i, r); +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + scanf("%d", &a[i]); + + qsort(1, n); + + for (int i = 1; i <= n; i++) + printf("%d ", a[i]); + + return 0; +} \ No newline at end of file diff --git a/Search and Randomized Algorithms/RadixSort.cpp b/Search and Randomized Algorithms/RadixSort.cpp new file mode 100644 index 0000000..e49f878 --- /dev/null +++ b/Search and Randomized Algorithms/RadixSort.cpp @@ -0,0 +1,78 @@ +/************************************************************************************ + + Radix sort. O(N * len), where len - maximum length of numbers. + Based on problem 766 from informatics.mccme.ru: + http://informatics.mccme.ru/mod/statements/view3.php?id=1129&chapterid=766 + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +int n; +int a[MAXN]; +vector buckets[10]; +int power = 1; +int minNum, maxNum; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d", &n); + for (int i = 1; i <= n; i++) + scanf("%d", &a[i]); + + minNum = a[1]; + for (int i = 2; i <= n; i++) { + minNum = min(minNum, a[i]); + maxNum = max(maxNum, a[i]); + } + + for (int i = 1; i <= n; i++) + a[i] -= minNum; + + while (true) { + for (int i = 0; i < 10; i++) + buckets[i].clear(); + + for (int i = 1; i <= n; i++) { + int digit = (a[i] / power) % 10; + buckets[digit].push_back(a[i]); + } + + n = 0; + + for (int i = 0; i < 10; i++) + for (int j = 0; j < (int) buckets[i].size(); j++) { + n++; + a[n] = buckets[i][j]; + } + + power *= 10; + if (power > maxNum) + break; + } + + for (int i = 1; i <= n; i++) + printf("%d ", a[i] + minNum); + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/Aho-Corasick.cpp b/String Algorithms/Aho-Corasick.cpp new file mode 100644 index 0000000..1a1b126 --- /dev/null +++ b/String Algorithms/Aho-Corasick.cpp @@ -0,0 +1,137 @@ +/****************************************************************************** + + Aho-Corasick algorithm. + + This code finds all words in the text that contain any of the + initially given words. O(len of queries + sum len of initial strings) + + + Based on problem K from here: http://codeforces.ru/gym/100133 + +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +struct node { + int suff_link, par; + char c; + map < char, int > go; + bool is_word; + + node() { + suff_link = -1, par = -1; + is_word = false; + } +}; + +int n; +char s[MAXN]; +vector trie; + +void trieInsert(char s[MAXN]) { + int cur_node = 0; + int len = strlen(s); + for (int i = 0; i < len; i++) { + int go = trie[cur_node].go[s[i]]; + if (go == 0) { + node add; + add.par = cur_node; add.c = s[i]; + trie.push_back(add); + go = (int) trie.size() - 1; + trie[cur_node].go[s[i]] = go; + } + cur_node = go; + } + trie[cur_node].is_word = true; +} + +int go(int cur_node, char c); + +int getSuffLink(int cur_node) { + if (trie[cur_node].suff_link != -1) + return trie[cur_node].suff_link; + if (trie[cur_node].par == 0) + return trie[cur_node].suff_link = 0; + char c = trie[cur_node].c; + int parent = trie[cur_node].par; + return trie[cur_node].suff_link = go(trie[parent].suff_link, c); +} + +int go(int cur_node, char c) { + if (trie[cur_node].go.count(c) > 0) + return trie[cur_node].go[c]; + if (cur_node == 0) + return trie[cur_node].go[c] = 0; + int suff_link = getSuffLink(cur_node); + return trie[cur_node].go[c] = go(suff_link, c); +} + +void buildAhoCorasick() { + queue q; + q.push(0); + while (!q.empty()) { + int cur_node = q.front(); + q.pop(); + + for (map :: iterator it = trie[cur_node].go.begin(); it != trie[cur_node].go.end(); it++) { + q.push(it->second); + } + + int suff_link = getSuffLink(cur_node); + trie[cur_node].suff_link = suff_link; + if (trie[suff_link].is_word) + trie[cur_node].is_word = true; + } +} + +int main() { + assert(freopen("console.in","r",stdin)); + assert(freopen("console.out","w",stdout)); + + node root; + root.suff_link = 0; + trie.push_back(root); + + scanf("%d", &n); + gets(s); + + for (int i = 1; i <= n; i++) { + gets(s); + trieInsert(s); + } + + buildAhoCorasick(); + + while (gets(s)) { + int cur_node = 0; + int len = strlen(s); + for (int i = 0; i < len; i++) { + cur_node = go(cur_node, s[i]); + if (trie[cur_node].is_word) { + puts(s); + break; + } + } + } + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/Hashing.cpp b/String Algorithms/Hashing.cpp new file mode 100644 index 0000000..f655e43 --- /dev/null +++ b/String Algorithms/Hashing.cpp @@ -0,0 +1,90 @@ +/****************************************************************************** + + Hashing in strings based problems. + + This code compares substrings using two hashes (one + uses 2^64 as a modulo, another 10^9 + 7) + + Based on problem C from here: http://codeforces.ru/gym/100133 + +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; +const int mod = (int) 1e9 + 7; +const int p = 53; + +string s; +int n, m; +long long h1[MAXN], h2[MAXN]; +long long pp1[MAXN], pp2[MAXN]; + +long long getHash1(int l, int r) { + l--; r--; + long long h = h1[r]; + if (l > 0) + h -= h1[l - 1]; + h *= pp1[n - 1 - r]; + return h; +} + +long long getHash2(int l, int r) { + l--; r--; + long long h = h2[r]; + if (l > 0) + h = (h - h2[l - 1] + mod) % mod; + h = (h * pp2[n - 1 - r]) % mod; + return h; +} + +int main() { + assert(freopen("substrcmp.in","r",stdin)); + assert(freopen("substrcmp.out","w",stdout)); + + getline(cin, s); + n = (int) s.length(); + + pp1[0] = 1; pp2[0] = 1; + for (int i = 1; i <= n; i++) { + pp1[i] = pp1[i - 1] * p; + pp2[i] = (pp2[i - 1] * p) % mod; + } + + h1[0] = s[0] - 'a' + 1; + h2[0] = (s[0] - 'a' + 1) % mod; + for (int i = 1; i < n; i++) { + h1[i] = h1[i - 1] + pp1[i] * (s[i] - 'a' + 1); + h2[i] = (h2[i - 1] + pp2[i] * (s[i] - 'a' + 1)) % mod; + } + + scanf("%d", &m); + + for (int i = 1; i <= m; i++) { + int a, b, c, d; + scanf("%d %d %d %d", &a, &b, &c, &d); + if (getHash1(a, b) == getHash1(c, d) && getHash2(a, b) == getHash2(c, d)) + puts("Yes"); + else + puts("No"); + } + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/ManacherPalindromes.cpp b/String Algorithms/ManacherPalindromes.cpp new file mode 100644 index 0000000..38f227b --- /dev/null +++ b/String Algorithms/ManacherPalindromes.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** + + Manacher's algorithm for finding all subpalindromes in the string. + + Based on problem L from here: http://codeforces.ru/gym/100133 + +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +string s; +int n; +int odd[MAXN], even[MAXN]; +int l, r; +long long ans; + +int main() { + assert(freopen("palindrome.in","r",stdin)); + assert(freopen("palindrome.out","w",stdout)); + + getline(cin, s); + n = (int) s.length(); + + // Odd case + l = r = -1; + for (int i = 0; i < n; i++) { + int cur = 1; + if (i < r) + cur = min(r - i + 1, odd[l + r - i]); + while (i + cur < n && i - cur >= 0 && s[i - cur] == s[i + cur]) + cur++; + odd[i] = cur; + if (i + cur - 1 > r) { + l = i - cur + 1; + r = i + cur - 1; + } + } + + // Even case + l = r = -1; + for (int i = 0; i < n; i++) { + int cur = 0; + if (i < r) + cur = min(r - i + 1, even[l + r - i + 1]); + while (i + cur < n && i - 1 - cur >= 0 && s[i - 1 - cur] == s[i + cur]) + cur++; + even[i] = cur; + if (i + cur - 1 > r) { + l = i - cur; + r = i + cur - 1; + } + } + + for (int i = 0; i < n; i++) { + if (odd[i] > 1) { + ans += odd[i] - 1; + } + if (even[i]) + ans += even[i]; + } + + cout << ans << endl; + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/PalindromeTree.cpp b/String Algorithms/PalindromeTree.cpp new file mode 100644 index 0000000..9cfe42c --- /dev/null +++ b/String Algorithms/PalindromeTree.cpp @@ -0,0 +1,107 @@ +/************************************************************************************** + + Palindrome tree. Useful structure to deal with palindromes in strings. O(N) + + This code counts number of palindrome substrings of the string. + Based on problem 1750 from informatics.mccme.ru: + http://informatics.mccme.ru/moodle/mod/statements/view.php?chapterid=1750 + +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 105000; + +struct node { + int next[26]; + int len; + int sufflink; + int num; +}; + +int len; +char s[MAXN]; +node tree[MAXN]; +int num; // node 1 - root with len -1, node 2 - root with len 0 +int suff; // max suffix palindrome +long long ans; + +bool addLetter(int pos) { + int cur = suff, curlen = 0; + int let = s[pos] - 'a'; + + while (true) { + curlen = tree[cur].len; + if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) + break; + cur = tree[cur].sufflink; + } + if (tree[cur].next[let]) { + suff = tree[cur].next[let]; + return false; + } + + num++; + suff = num; + tree[num].len = tree[cur].len + 2; + tree[cur].next[let] = num; + + if (tree[num].len == 1) { + tree[num].sufflink = 2; + tree[num].num = 1; + return true; + } + + while (true) { + cur = tree[cur].sufflink; + curlen = tree[cur].len; + if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) { + tree[num].sufflink = tree[cur].next[let]; + break; + } + } + + tree[num].num = 1 + tree[tree[num].sufflink].num; + + return true; +} + +void initTree() { + num = 2; suff = 2; + tree[1].len = -1; tree[1].sufflink = 1; + tree[2].len = 0; tree[2].sufflink = 1; +} + +int main() { + //assert(freopen("input.txt", "r", stdin)); + //assert(freopen("output.txt", "w", stdout)); + + gets(s); + len = strlen(s); + + initTree(); + + for (int i = 0; i < len; i++) { + addLetter(i); + ans += tree[suff].num; + } + + cout << ans << endl; + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/PrefixFunction.cpp b/String Algorithms/PrefixFunction.cpp new file mode 100644 index 0000000..747fe45 --- /dev/null +++ b/String Algorithms/PrefixFunction.cpp @@ -0,0 +1,56 @@ +/************************************************************************************* + + Prefix function. O(N) + + About it: http://e-maxx.ru/algo/prefix_function + Based on problem 1323 from informatics.mccme.ru: + http://informatics.mccme.ru/mod/statements/view3.php?id=241&chapterid=1323 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1000100; + +int n; +string s; +int p[MAXN]; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + getline(cin, s); + n = (int) s.length(); + + for (int i = 2; i <= n; i++) { + int prev = p[i - 1]; + while (prev > 0 && s[prev] != s[i - 1]) + prev = p[prev]; + if (s[prev] == s[i - 1]) + prev++; + p[i] = prev; + } + + for (int i = 1; i <= n; i++) + printf("%d ", p[i]); + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/SuffixArray.cpp b/String Algorithms/SuffixArray.cpp new file mode 100644 index 0000000..8d36c09 --- /dev/null +++ b/String Algorithms/SuffixArray.cpp @@ -0,0 +1,153 @@ +/************************************************************************ + + Suffix Array. Builing works in O(NlogN). + Also LCP array is calculated in O(NlogN). + + This code counts number of different substrings in the string. + Based on problem I from here: http://codeforces.ru/gym/100133 + +************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 205000; +const int ALPH = 256; +const int MAXLOG = 20; + +int n; +char s[MAXN]; +int p[MAXN]; // suffix array itself +int pcur[MAXN]; +int c[MAXN][MAXLOG]; +int num[MAXN]; +int classesNum; +int lcp[MAXN]; + +void buildSuffixArray() { + n++; + + for (int i = 0; i < n; i++) + num[s[i]]++; + + for (int i = 1; i < ALPH; i++) + num[i] += num[i - 1]; + + for (int i = 0; i < n; i++) { + p[num[s[i]] - 1] = i; + num[s[i]]--; + } + + c[p[0]][0] = 1; + classesNum = 1; + for (int i = 1; i < n; i++) { + if (s[p[i]] != s[p[i - 1]]) + classesNum++; + c[p[i]][0] = classesNum; + } + + for (int i = 1; ; i++) { + + int half = (1 << (i - 1)); + + for (int j = 0; j < n; j++) { + pcur[j] = p[j] - half; + if (pcur[j] < 0) + pcur[j] += n; + } + + for (int j = 1; j <= classesNum; j++) + num[j] = 0; + + for (int j = 0; j < n; j++) + num[c[pcur[j]][i - 1]]++; + for (int j = 2; j <= classesNum; j++) + num[j] += num[j - 1]; + + for (int j = n - 1; j >= 0; j--) { + p[num[c[pcur[j]][i - 1]] - 1] = pcur[j]; + num[c[pcur[j]][i - 1]]--; + } + + c[p[0]][i] = 1; + classesNum = 1; + + for (int j = 1; j < n; j++) { + int p1 = (p[j] + half) % n, p2 = (p[j - 1] + half) % n; + if (c[p[j]][i - 1] != c[p[j - 1]][i - 1] || c[p1][i - 1] != c[p2][i - 1]) + classesNum++; + c[p[j]][i] = classesNum; + } + + if ((1 << i) >= n) + break; + } + + for (int i = 0; i < n; i++) + p[i] = p[i + 1]; + n--; +} + +int getLcp(int a, int b) { + int res = 0; + for (int i = MAXLOG - 1; i >= 0; i--) { + int curlen = (1 << i); + if (curlen > n) + continue; + if (c[a][i] == c[b][i]) { + res += curlen; + a += curlen; + b += curlen; + } + } + return res; +} + +void calcLcpArray() { + for (int i = 0; i < n - 1; i++) + lcp[i] = getLcp(p[i], p[i + 1]); +} + +int main() { + assert(freopen("substr.in","r",stdin)); + assert(freopen("substr.out","w",stdout)); + + gets(s); + n = strlen(s); + + buildSuffixArray(); + + // Now p from 0 to n - 1 contains suffix array of original string + + /*for (int i = 0; i < n; i++) { + printf("%d ", p[i] + 1); + }*/ + + calcLcpArray(); + + long long ans = 0; + for (int i = 0; i < n; i++) + ans += n - p[i]; + for (int i = 1; i < n; i++) + ans -= lcp[i - 1]; + + cout << ans << endl; + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/Trie.cpp b/String Algorithms/Trie.cpp new file mode 100644 index 0000000..532de37 --- /dev/null +++ b/String Algorithms/Trie.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** + + Trie. Builds tree from the set of strings. O(total length of strings) + + This code counts number of different substrings in the string. + Based on problem B from here: http://codeforces.ru/gym/100133 + +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int ALPH = 26; +const int MAXN = 100500; + +struct node { + int go[ALPH]; +}; + +string s; +node trie[MAXN]; +int node_num; + +int main() { + assert(freopen("unequal.in","r",stdin)); + assert(freopen("unequal.out","w",stdout)); + + getline(cin, s); + + for (int i = 0; i < (int) s.length(); i++) { + int cur = 0; + for (int j = i; j < (int) s.length(); j++) { + int ch = s[j] - 'a'; + if (trie[cur].go[ch] == 0) { + node_num++; + trie[cur].go[ch] = node_num; + } + cur = trie[cur].go[ch]; + } + } + + printf("%d\n", node_num); + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/UkkonenSuffixTree.cpp b/String Algorithms/UkkonenSuffixTree.cpp new file mode 100644 index 0000000..83e36e2 --- /dev/null +++ b/String Algorithms/UkkonenSuffixTree.cpp @@ -0,0 +1,182 @@ +/************************************************************************ + + Suffix Tree. Ukkonen's algorithm using sibling lists O(N). + + This code counts number of different substrings in the string. + Based on problem I from here: http://codeforces.ru/gym/100133 + +************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define root 1 + +const int MAXN = 105000; +const int inf = 1000 * 1000 * 1000; + +struct node { + int from, to, link; + int child, bro; +}; + +int n, len, nk, pos; +string s; +vector tree; +int active_e, active_node, active_len, needSL, rem; + +int add_node(int from, int to) { + nk++; + node temp; + temp.from = from; temp.to = to; temp.link = 0; + temp.child = 0; temp.bro = 0; + tree.push_back(temp); + return nk; +} + +void st_init() { + nk = -1; + pos = -1; + rem = active_e = active_len = needSL = 0; + active_node = root; + add_node(-1, -1); + add_node(-1, -1); +} + +void addSL(int v) { + if (needSL) tree[needSL].link = v; + needSL = v; +} + +int find_edge(int v, int c) { + v = tree[v].child; + while (v) { + if (s[tree[v].from] == c) + return v; + v = tree[v].bro; + } + return 0; +} + +void insert_edge(int v, int to) { + int temp = tree[v].child; + tree[v].child = to; + tree[to].bro = temp; +} + +void change_edge(int v, int c, int to) { + int next = tree[v].child; + if (s[tree[next].from] == c) { + tree[v].child = to; + tree[to].bro = tree[next].bro; + return; + } + v = next; + while (v) { + next = tree[v].bro; + if (s[tree[next].from] == c) { + tree[v].bro = to; + tree[to].bro = tree[next].bro; + return; + } + v = next; + } +} + +bool walk_down(int v) { + int elen = tree[v].to - tree[v].from; + if (tree[v].from + active_len >= tree[v].to) { + active_node = v; + active_len -= elen; + active_e += elen; + return true; + } + return false; +} + +int active_edge() { + return s[active_e]; +} + +void st_insert(int c) { + pos++; + needSL = 0; rem++; + while (rem) { + if (active_len == 0) active_e = pos; + int go = find_edge(active_node, active_edge()); + if (go == 0) { + int leaf = add_node(pos, inf); + insert_edge(active_node, leaf); + addSL(active_node); + } + else { + if (walk_down(go)) + continue; + if (s[tree[go].from + active_len] == c) { + active_len++; + addSL(active_node); + break; + } + int split = add_node(tree[go].from, tree[go].from + active_len); + int leaf = add_node(pos, inf); + + change_edge(active_node, active_edge(), split); + insert_edge(split, go); + insert_edge(split, leaf); + + tree[go].from = tree[go].from + active_len; + + addSL(split); + } + rem--; + if (active_node == root && active_len) { + active_len--; + active_e = pos - rem + 1; + } + else { + if (tree[active_node].link) + active_node = tree[active_node].link; + else + active_node = root; + } + } +} + +int count_diff() { + int result = 0; + for (int i = 2; i <= nk; i++) + result += min(tree[i].to, n) - tree[i].from; + return result; +} + +int main() { + freopen("substr.in","r",stdin); + freopen("substr.out","w",stdout); + + getline(cin, s); + n = (int) s.length(); + + st_init(); + for (int i = 0; i < n; i++) + st_insert(s[i]); + + printf("%d", count_diff()); + + return 0; +} \ No newline at end of file diff --git a/String Algorithms/ZFunction.cpp b/String Algorithms/ZFunction.cpp new file mode 100644 index 0000000..2337ade --- /dev/null +++ b/String Algorithms/ZFunction.cpp @@ -0,0 +1,62 @@ +/************************************************************************************* + + Z function. O(N) + + About it: http://e-maxx.ru/algo/z_function + Based on problem 1324 from informatics.mccme.ru: + http://informatics.mccme.ru/mod/statements/view3.php?id=241&chapterid=1324 + +*************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1000100; + +string s; +int n; +int z[MAXN]; +int l, r; + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + getline(cin, s); + n = (int) s.length(); + + l = r = 0; + for (int i = 2; i <= n; i++) { + int cur = 0; + if (i <= r) + cur = min(r - i + 1, z[i - l + 1]); + while (i + cur <= n && s[i + cur - 1] == s[cur]) + cur++; + if (i + cur - 1 > r) { + l = i; r = i + cur - 1; + } + z[i] = cur; + } + + z[1] = n; + for (int i = 1; i <= n; i++) + printf("%d ", z[i]); + + return 0; +} \ No newline at end of file From 4c36db1e26168b93032ce9b0bca52c475544ebe2 Mon Sep 17 00:00:00 2001 From: Akul Mehra Date: Sat, 10 Oct 2015 19:13:36 +0530 Subject: [PATCH 4/9] geometry and maths --- Computational Geometry/convex_hull.cpp | 60 +++++++ .../general_geometry_library.cpp | 165 ++++++++++++++++++ Computational Geometry/polygon_cut.cpp | 46 +++++ 3 files changed, 271 insertions(+) create mode 100644 Computational Geometry/convex_hull.cpp create mode 100644 Computational Geometry/general_geometry_library.cpp create mode 100644 Computational Geometry/polygon_cut.cpp diff --git a/Computational Geometry/convex_hull.cpp b/Computational Geometry/convex_hull.cpp new file mode 100644 index 0000000..6d775fe --- /dev/null +++ b/Computational Geometry/convex_hull.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +using namespace std; +const double eps = 1e-9; +inline int diff(double lhs, double rhs) { + if (lhs - eps < rhs && rhs < lhs + eps) return 0; + return (lhs < rhs) ? -1 : 1; +} +struct Point { + double x, y; + Point() {} + Point(double x_, double y_): x(x_), y(y_) {} + +}; +inline int ccw(const Point& a, const Point& b, const Point& c) { + return diff(a.x * b.y + b.x * c.y + c.x * a.y + - a.y * b.x - b.y * c.x - c.y * a.x, 0); +} +inline double dist2(const Point &a, const Point &b) { + double dx = a.x - b.x; + double dy = a.y - b.y; + return dx * dx + dy * dy; +} +struct PointSorter { + Point origin; + PointSorter(const vector& points) { + origin = points[0]; + for (int i = 1 ; i < points.size() ; i++) { + int det = diff(origin.x, points[i].x); + if (det > 0) + origin = points[i]; + else if (det == 0 && diff(origin.y, points[i].y) > 0) + origin = points[i]; + } + } + bool operator()(const Point &a, const Point &b) { + if (diff(b.x, origin.x) == 0 && diff(b.y, origin.y) == 0) return false; + if (diff(a.x, origin.x) == 0 && diff(a.y, origin.y) == 0) return true; + int det = ccw(origin, a, b); + if (det == 0) return dist2(a, origin) < dist2(b, origin); + return det < 0; + } +}; +vector convex_hull(vector points) { + if (points.size() <= 3) + return points; + PointSorter cmp(points); + sort(points.begin(), points.end(), cmp); + vector ans; + ans.push_back(points[0]); + ans.push_back(points[1]); + for (int i = 2 ; i < points.size() ; i++) { + while (ans.size() > 1 && + ccw(ans[ans.size() - 2], ans[ans.size() - 1], points[i]) >= 0) + ans.pop_back(); + ans.push_back(points[i]); + } + return ans; +} \ No newline at end of file diff --git a/Computational Geometry/general_geometry_library.cpp b/Computational Geometry/general_geometry_library.cpp new file mode 100644 index 0000000..55250a2 --- /dev/null +++ b/Computational Geometry/general_geometry_library.cpp @@ -0,0 +1,165 @@ +#include +#include +using namespace std; +const double eps = 1e-9; +inline int diff(double lhs, double rhs) { + if (lhs - eps < rhs && rhs < lhs + eps) return 0; + return (lhs < rhs) ? -1 : 1; +} +inline bool is_between(double check, double a, double b) { + if (a < b) + return (a - eps < check && check < b + eps); + else + return (b - eps < check && check < a + eps); +} +struct Point { + double x, y; + Point() {} + Point(double x_, double y_): x(x_), y(y_) {} + bool operator==(const Point& rhs) const { + return diff(x, rhs.x) == 0 && diff(y, rhs.y) == 0; + } + const Point operator+(const Point& rhs) const { + return Point(x + rhs.x, y + rhs.y); + } + const Point operator-(const Point& rhs) const { + return Point(x - rhs.x, y - rhs.y); + } + const Point operator*(double t) const { + return Point(x * t, y * t); + } +}; +Seoul National University 19 +struct Circle { + Point center; + double r; + Circle() {} + Circle(const Point& center_, double r_): center(center_), r(r_) {} +}; +struct Line { + Point pos, dir; + Line() {} + Line(const Point& pos_, const Point& dir_): pos(pos_), dir(dir_) {} +}; +inline double inner(const Point& a, const Point& b) { + return a.x * b.x + a.y * b.y; +} +inline double outer(const Point& a, const Point& b) { + return a.x * b.y - a.y * b.x; +} +inline int ccw_line(const Line& line, const Point& point) { + return diff(outer(line.dir, point - line.pos), 0); +} +inline int ccw(const Point& a, const Point& b, const Point& c) { + return diff(outer(b - a, c - a), 0); +} +inline double dist(const Point& a, const Point& b) { + return sqrt(inner(a - b, a - b)); +} +inline double dist2(const Point &a, const Point &b) { + return inner(a - b, a - b); +} +inline double dist(const Line& line, const Point& point, bool segment = false) { + double c1 = inner(point - line.pos, line.dir); + if (segment && diff(c1, 0) <= 0) return dist(line.pos, point); + double c2 = inner(line.dir, line.dir); + if (segment && diff(c2, c1) <= 0) return dist(line.pos + line.dir, point); + return dist(line.pos + line.dir * (c1 / c2), point); +} +bool get_cross(const Line& a, const Line& b, Point& ret) { + double mdet = outer(b.dir, a.dir); + if (diff(mdet, 0) == 0) return false; + double t2 = outer(a.dir, b.pos - a.pos) / mdet; + ret = b.pos + b.dir * t2; + return true; +} +bool get_segment_cross(const Line& a, const Line& b, Point& ret) { + double mdet = outer(b.dir, a.dir); + if (diff(mdet, 0) == 0) return false; + double t1 = -outer(b.pos - a.pos, b.dir) / mdet; + double t2 = outer(a.dir, b.pos - a.pos) / mdet; + if (!is_between(t1, 0, 1) || !is_between(t2, 0, 1)) return false; + ret = b.pos + b.dir * t2; + return true; +} +const Point inner_center(const Point &a, const Point &b, const Point &c) { + double wa = dist(b, c), wb = dist(c, a), wc = dist(a, b); + double w = wa + wb + wc; + return Point( + (wa * a.x + wb * b.x + wc * c.x) / w, + (wa * a.y + wb * b.y + wc * c.y) / w); +} +const Point outer_center(const Point &a, const Point &b, const Point &c) { + Point d1 = b - a, d2 = c - a; + double area = outer(d1, d2); + double dx = d1.x * d1.x * d2.y - d2.x * d2.x * d1.y + + d1.y * d2.y * (d1.y - d2.y); + double dy = d1.y * d1.y * d2.x - d2.y * d2.y * d1.x + + d1.x * d2.x * (d1.x - d2.y); + return Point(a.x + dx / area / 2.0, a.y - dy / area / 2.0); +} +vector circle_line(const Circle& circle, const Line& line) { + vector result; + double a = 2 * inner(line.dir, line.dir); + double b = 2 * (line.dir.x * (line.pos.x - circle.center.x) + + line.dir.y * (line.pos.y - circle.center.y)); + double c = inner(line.pos - circle.center, line.pos - circle.center) + - circle.r * circle.r; + double det = b * b - 2 * a * c; + int pred = diff(det, 0); + Seoul National University 20 + if (pred == 0) + result.push_back(line.pos + line.dir * (-b / a)); + else if (pred > 0) { + det = sqrt(det); + result.push_back(line.pos + line.dir * ((-b + det) / a)); + result.push_back(line.pos + line.dir * ((-b - det) / a)); + } + return result; +} +vector circle_circle(const Circle& a, const Circle& b) { + vector result; + int pred = diff(dist(a.center, b.center), a.r + b.r); + if (pred > 0) return result; + if (pred == 0) { + result.push_back((a.center * b.r + b.center * a.r) * (1 / (a.r + b.r))); + return result; + } + double aa = a.center.x * a.center.x + a.center.y * a.center.y - a.r * a.r; + double bb = b.center.x * b.center.x + b.center.y * b.center.y - b.r * b.r; + double tmp = (bb - aa) / 2.0; + Point cdiff = b.center - a.center; + if (diff(cdiff.x, 0) == 0) { + if (diff(cdiff.y, 0) == 0) + return result; // if (diff(a.r, b.r) == 0): same circle + return circle_line(a, Line(Point(0, tmp / cdiff.y), Point(1, 0))); + } + return circle_line(a, + Line(Point(tmp / cdiff.x, 0), Point(-cdiff.y, cdiff.x))); +} +const Circle circle_from_3pts(const Point& a, const Point& b, const Point& c) { + Point ba = b - a, cb = c - b; + Line p((a + b) * 0.5, Point(ba.y, -ba.x)); + Line q((b + c) * 0.5, Point(cb.y, -cb.x)); + Circle circle; + if (!get_cross(p, q, circle.center)) + circle.r = -1; + else + circle.r = dist(circle.center, a); + return circle; +} +const Circle circle_from_2pts_rad(const Point& a, const Point& b, double r) { + double det = r * r / dist2(a, b) - 0.25; + Circle circle; + if (det < 0) + circle.r = -1; + else { + double h = sqrt(det); +// center is to the left of a->b + circle.center = (a + b) * 0.5 + Point(a.y - b.y, b.x - a.x) * h; + circle.r = r; + } + return circle; +} + + diff --git a/Computational Geometry/polygon_cut.cpp b/Computational Geometry/polygon_cut.cpp new file mode 100644 index 0000000..c78a132 --- /dev/null +++ b/Computational Geometry/polygon_cut.cpp @@ -0,0 +1,46 @@ +// left side of a->b +vector cut_polygon(const vector& polygon, Line line) { + if (!polygon.size()) return polygon; + typedef vector::const_iterator piter; + piter la, lan, fi, fip, i, j; + la = lan = fi = fip = polygon.end(); + i = polygon.end() - 1; + bool lastin = diff(ccw_line(line, polygon[polygon.size() - 1]), 0) > 0; + for (j = polygon.begin() ; j != polygon.end() ; j++) { + bool thisin = diff(ccw_line(line, *j), 0) > 0; + if (lastin && !thisin) { + la = i; + lan = j; + } + if (!lastin && thisin) { + fi = j; + fip = i; + } + i = j; + lastin = thisin; + } + if (fi == polygon.end()) { + if (!lastin) return vector(); + return polygon; + } + vector result; + for (i = fi ; i != lan ; i++) { + if (i == polygon.end()) { + i = polygon.begin(); + if (i == lan) break; + } + result.push_back(*i); + Seoul National University 21 + + } + Point lc, fc; + get_cross(Line(*la, *lan + - *la), line, lc); + get_cross(Line(*fip, *fi + - *fip), line, fc); + result.push_back(lc); + if (diff(dist2(lc, fc), 0) != 0) result.push_back(fc); + return result; +} + + From dfc76ea10725a29df49bfa0185f11eb7e69b1044 Mon Sep 17 00:00:00 2001 From: Manoj Pandey Date: Sat, 10 Oct 2015 19:18:50 +0530 Subject: [PATCH 5/9] added flow_networks algos --- Basic Geometry/geometry.cpp | 299 ++++++++++++++++++ Flow Networks & Matching/Dinic.cpp | 146 +++++++++ Flow Networks & Matching/FordFulkerson.cpp | 104 ++++++ .../maxBipartiteMatching.cpp | 41 +++ Flow Networks & Matching/minCostMatching.cpp | 129 ++++++++ Flow Networks & Matching/minCostMaxFlow.cpp | 100 ++++++ Flow Networks & Matching/minCut.cpp | 54 ++++ Flow Networks & Matching/pushRelabel.cpp | 116 +++++++ 8 files changed, 989 insertions(+) create mode 100644 Basic Geometry/geometry.cpp create mode 100644 Flow Networks & Matching/Dinic.cpp create mode 100644 Flow Networks & Matching/FordFulkerson.cpp create mode 100644 Flow Networks & Matching/maxBipartiteMatching.cpp create mode 100644 Flow Networks & Matching/minCostMatching.cpp create mode 100644 Flow Networks & Matching/minCostMaxFlow.cpp create mode 100644 Flow Networks & Matching/minCut.cpp create mode 100644 Flow Networks & Matching/pushRelabel.cpp diff --git a/Basic Geometry/geometry.cpp b/Basic Geometry/geometry.cpp new file mode 100644 index 0000000..037f624 --- /dev/null +++ b/Basic Geometry/geometry.cpp @@ -0,0 +1,299 @@ +#include +#include +#include +#include + +using namespace std; + +double INF = 1e100; +double EPS = 1e-12; + +struct PT { + double x, y; + PT() {} + PT(double x, double y) : x(x), y(y) {} + PT(const PT &p) : x(p.x), y(p.y) {} + PT operator + (const PT &p) const { return PT(x + p.x, y + p.y); } + PT operator - (const PT &p) const { return PT(x - p.x, y - p.y); } + PT operator * (double c) const { return PT(x * c, y * c ); } + PT operator / (double c) const { return PT(x / c, y / c ); } +}; + +double dot(PT p, PT q) { return p.x * q.x + p.y * q.y; } +double dist2(PT p, PT q) { return dot(p - q, p - q); } +double cross(PT p, PT q) { return p.x * q.y - p.y * q.x; } +ostream &operator<<(ostream &os, const PT &p) { + os << "(" << p.x << "," << p.y << ")"; +} + +// rotate a point CCW or CW around the origin +PT RotateCCW90(PT p) { return PT(-p.y, p.x); } +PT RotateCW90(PT p) { return PT(p.y, -p.x); } +PT RotateCCW(PT p, double t) { + return PT(p.x * cos(t) - p.y * sin(t), p.x * sin(t) + p.y * cos(t)); +} + +// project point c onto line through a and b +// assuming a != b +PT ProjectPointLine(PT a, PT b, PT c) { + return a + (b - a) * dot(c - a, b - a) / dot(b - a, b - a); +} + +// project point c onto line segment through a and b +PT ProjectPointSegment(PT a, PT b, PT c) { + double r = dot(b - a, b - a); + if (fabs(r) < EPS) return a; + r = dot(c - a, b - a) / r; + if (r < 0) return a; + if (r > 1) return b; + return a + (b - a) * r; +} + +// compute distance from c to segment between a and b +double DistancePointSegment(PT a, PT b, PT c) { + return sqrt(dist2(c, ProjectPointSegment(a, b, c))); +} + +// compute distance between point (x,y,z) and plane ax+by+cz=d +double DistancePointPlane(double x, double y, double z, + double a, double b, double c, double d) +{ + return fabs(a * x + b * y + c * z - d) / sqrt(a * a + b * b + c * c); +} + +// determine if lines from a to b and c to d are parallel or collinear +bool LinesParallel(PT a, PT b, PT c, PT d) { + return fabs(cross(b - a, c - d)) < EPS; +} + +bool LinesCollinear(PT a, PT b, PT c, PT d) { + return LinesParallel(a, b, c, d) + && fabs(cross(a - b, a - c)) < EPS + && fabs(cross(c - d, c - a)) < EPS; +} + +// determine if line segment from a to b intersects with +// line segment from c to d +bool SegmentsIntersect(PT a, PT b, PT c, PT d) { + if (LinesCollinear(a, b, c, d)) { + if (dist2(a, c) < EPS || dist2(a, d) < EPS || + dist2(b, c) < EPS || dist2(b, d) < EPS) return true; + if (dot(c - a, c - b) > 0 && dot(d - a, d - b) > 0 && dot(c - b, d - b) > 0) + return false; + return true; + } + if (cross(d - a, b - a) * cross(c - a, b - a) > 0) return false; + if (cross(a - c, d - c) * cross(b - c, d - c) > 0) return false; + return true; +} + +// compute intersection of line passing through a and b +// with line passing through c and d, assuming that unique +// intersection exists; for segment intersection, check if +// segments intersect first +PT ComputeLineIntersection(PT a, PT b, PT c, PT d) { + b = b - a; d = c - d; c = c - a; + assert(dot(b, b) > EPS && dot(d, d) > EPS); + return a + b * cross(c, d) / cross(b, d); +} + +// compute center of circle given three points +PT ComputeCircleCenter(PT a, PT b, PT c) { + b = (a + b) / 2; + c = (a + c) / 2; + return ComputeLineIntersection(b, b + RotateCW90(a - b), c, c + RotateCW90(a - c)); +} + +// determine if point is in a possibly non-convex polygon (by William +// Randolph Franklin); returns 1 for strictly interior points, 0 for +// strictly exterior points, and 0 or 1 for the remaining points. +// Note that it is possible to convert this into an *exact* test using +// integer arithmetic by taking care of the division appropriately +// (making sure to deal with signs properly) and then by writing exact +// tests for checking point on polygon boundary +bool PointInPolygon(const vector &p, PT q) { + bool c = 0; + for (int i = 0; i < p.size(); i++) { + int j = (i + 1) % p.size(); + if ((p[i].y <= q.y && q.y < p[j].y || + p[j].y <= q.y && q.y < p[i].y) && + q.x < p[i].x + (p[j].x - p[i].x) * (q.y - p[i].y) / (p[j].y - p[i].y)) + c = !c; + } + return c; +} + +// determine if point is on the boundary of a polygon +bool PointOnPolygon(const vector &p, PT q) { + for (int i = 0; i < p.size(); i++) + if (dist2(ProjectPointSegment(p[i], p[(i + 1) % p.size()], q), q) < EPS) + return true; + return false; +} + +// compute intersection of line through points a and b with +// circle centered at c with radius r > 0 +vector CircleLineIntersection(PT a, PT b, PT c, double r) { + vector ret; + b = b - a; + a = a - c; + double A = dot(b, b); + double B = dot(a, b); + double C = dot(a, a) - r * r; + double D = B * B - A * C; + if (D < -EPS) return ret; + ret.push_back(c + a + b * (-B + sqrt(D + EPS)) / A); + if (D > EPS) + ret.push_back(c + a + b * (-B - sqrt(D)) / A); + return ret; +} + +// compute intersection of circle centered at a with radius r +// with circle centered at b with radius R +vector CircleCircleIntersection(PT a, PT b, double r, double R) { + vector ret; + double d = sqrt(dist2(a, b)); + if (d > r + R || d + min(r, R) < max(r, R)) return ret; + double x = (d * d - R * R + r * r) / (2 * d); + double y = sqrt(r * r - x * x); + PT v = (b - a) / d; + ret.push_back(a + v * x + RotateCCW90(v)*y); + if (y > 0) + ret.push_back(a + v * x - RotateCCW90(v)*y); + return ret; +} + +// This code computes the area or centroid of a (possibly nonconvex) +// polygon, assuming that the coordinates are listed in a clockwise or +// counterclockwise fashion. Note that the centroid is often known as +// the "center of gravity" or "center of mass". +double ComputeSignedArea(const vector &p) { + double area = 0; + for (int i = 0; i < p.size(); i++) { + int j = (i + 1) % p.size(); + area += p[i].x * p[j].y - p[j].x * p[i].y; + } + return area / 2.0; +} + +double ComputeArea(const vector &p) { + return fabs(ComputeSignedArea(p)); +} + +PT ComputeCentroid(const vector &p) { + PT c(0, 0); + double scale = 6.0 * ComputeSignedArea(p); + for (int i = 0; i < p.size(); i++) { + int j = (i + 1) % p.size(); + c = c + (p[i] + p[j]) * (p[i].x * p[j].y - p[j].x * p[i].y); + } + return c / scale; +} + +// tests whether or not a given polygon (in CW or CCW order) is simple +bool IsSimple(const vector &p) { + for (int i = 0; i < p.size(); i++) { + for (int k = i + 1; k < p.size(); k++) { + int j = (i + 1) % p.size(); + int l = (k + 1) % p.size(); + if (i == l || j == k) continue; + if (SegmentsIntersect(p[i], p[j], p[k], p[l])) + return false; + } + } + return true; +} + +int main() { + + // expected: (-5,2) + cerr << RotateCCW90(PT(2, 5)) << endl; + + // expected: (5,-2) + cerr << RotateCW90(PT(2, 5)) << endl; + + // expected: (-5,2) + cerr << RotateCCW(PT(2, 5), M_PI / 2) << endl; + + // expected: (5,2) + cerr << ProjectPointLine(PT(-5, -2), PT(10, 4), PT(3, 7)) << endl; + + // expected: (5,2) (7.5,3) (2.5,1) + cerr << ProjectPointSegment(PT(-5, -2), PT(10, 4), PT(3, 7)) << " " + << ProjectPointSegment(PT(7.5, 3), PT(10, 4), PT(3, 7)) << " " + << ProjectPointSegment(PT(-5, -2), PT(2.5, 1), PT(3, 7)) << endl; + + // expected: 6.78903 + cerr << DistancePointPlane(4, -4, 3, 2, -2, 5, -8) << endl; + + // expected: 1 0 1 + cerr << LinesParallel(PT(1, 1), PT(3, 5), PT(2, 1), PT(4, 5)) << " " + << LinesParallel(PT(1, 1), PT(3, 5), PT(2, 0), PT(4, 5)) << " " + << LinesParallel(PT(1, 1), PT(3, 5), PT(5, 9), PT(7, 13)) << endl; + + // expected: 0 0 1 + cerr << LinesCollinear(PT(1, 1), PT(3, 5), PT(2, 1), PT(4, 5)) << " " + << LinesCollinear(PT(1, 1), PT(3, 5), PT(2, 0), PT(4, 5)) << " " + << LinesCollinear(PT(1, 1), PT(3, 5), PT(5, 9), PT(7, 13)) << endl; + + // expected: 1 1 1 0 + cerr << SegmentsIntersect(PT(0, 0), PT(2, 4), PT(3, 1), PT(-1, 3)) << " " + << SegmentsIntersect(PT(0, 0), PT(2, 4), PT(4, 3), PT(0, 5)) << " " + << SegmentsIntersect(PT(0, 0), PT(2, 4), PT(2, -1), PT(-2, 1)) << " " + << SegmentsIntersect(PT(0, 0), PT(2, 4), PT(5, 5), PT(1, 7)) << endl; + + // expected: (1,2) + cerr << ComputeLineIntersection(PT(0, 0), PT(2, 4), PT(3, 1), PT(-1, 3)) << endl; + + // expected: (1,1) + cerr << ComputeCircleCenter(PT(-3, 4), PT(6, 1), PT(4, 5)) << endl; + + vector v; + v.push_back(PT(0, 0)); + v.push_back(PT(5, 0)); + v.push_back(PT(5, 5)); + v.push_back(PT(0, 5)); + + // expected: 1 1 1 0 0 + cerr << PointInPolygon(v, PT(2, 2)) << " " + << PointInPolygon(v, PT(2, 0)) << " " + << PointInPolygon(v, PT(0, 2)) << " " + << PointInPolygon(v, PT(5, 2)) << " " + << PointInPolygon(v, PT(2, 5)) << endl; + + // expected: 0 1 1 1 1 + cerr << PointOnPolygon(v, PT(2, 2)) << " " + << PointOnPolygon(v, PT(2, 0)) << " " + << PointOnPolygon(v, PT(0, 2)) << " " + << PointOnPolygon(v, PT(5, 2)) << " " + << PointOnPolygon(v, PT(2, 5)) << endl; + + // expected: (1,6) + // (5,4) (4,5) + // blank line + // (4,5) (5,4) + // blank line + // (4,5) (5,4) + vector u = CircleLineIntersection(PT(0, 6), PT(2, 6), PT(1, 1), 5); + for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl; + u = CircleLineIntersection(PT(0, 9), PT(9, 0), PT(1, 1), 5); + for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl; + u = CircleCircleIntersection(PT(1, 1), PT(10, 10), 5, 5); + for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl; + u = CircleCircleIntersection(PT(1, 1), PT(8, 8), 5, 5); + for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl; + u = CircleCircleIntersection(PT(1, 1), PT(4.5, 4.5), 10, sqrt(2.0) / 2.0); + for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl; + u = CircleCircleIntersection(PT(1, 1), PT(4.5, 4.5), 5, sqrt(2.0) / 2.0); + for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl; + + // area should be 5.0 + // centroid should be (1.1666666, 1.166666) + PT pa[] = { PT(0, 0), PT(5, 0), PT(1, 1), PT(0, 5) }; + vector p(pa, pa + 4); + PT c = ComputeCentroid(p); + cerr << "Area: " << ComputeArea(p) << endl; + cerr << "Centroid: " << c << endl; + + return 0; +} \ No newline at end of file diff --git a/Flow Networks & Matching/Dinic.cpp b/Flow Networks & Matching/Dinic.cpp new file mode 100644 index 0000000..14c0003 --- /dev/null +++ b/Flow Networks & Matching/Dinic.cpp @@ -0,0 +1,146 @@ +/******************************************************************************** + + MaxFlow Dinic algorithm with scaling. + O(N * M * log(MC)), where MC is maximum edge capacity. + + Based on problem 2784 from informatics.mccme.ru + http://informatics.mccme.ru/mod/statements/view3.php?chapterid=2784#1 + +********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +struct edge { + int a, b, f, c; +}; + +const int inf = 1000 * 1000 * 1000; +const int MAXN = 1050; + +int n, m; +vector e; +int pt[MAXN]; // very important performance trick +vector g[MAXN]; +long long flow = 0; +queue q; +int d[MAXN]; +int lim; +int s, t; + +void add_edge(int a, int b, int c) { + edge ed; + + //keep edges in vector: e[ind] - direct edge, e[ind ^ 1] - back edge + + ed.a = a; ed.b = b; ed.f = 0; ed.c = c; + g[a].push_back(e.size()); + e.push_back(ed); + + ed.a = b; ed.b = a; ed.f = c; ed.c = c; + g[b].push_back(e.size()); + e.push_back(ed); +} + +bool bfs() { + for (int i = s; i <= t; i++) + d[i] = inf; + d[s] = 0; + q.push(s); + while (!q.empty() && d[t] == inf) { + int cur = q.front(); q.pop(); + for (size_t i = 0; i < g[cur].size(); i++) { + int id = g[cur][i]; + int to = e[id].b; + + //printf("cur = %d id = %d a = %d b = %d f = %d c = %d\n", cur, id, e[id].a, e[id].b, e[id].f, e[id].c); + + if (d[to] == inf && e[id].c - e[id].f >= lim) { + d[to] = d[cur] + 1; + q.push(to); + } + } + } + while (!q.empty()) + q.pop(); + return d[t] != inf; +} + +bool dfs(int v, int flow) { + if (flow == 0) + return false; + if (v == t) { + //cout << v << endl; + return true; + } + for (; pt[v] < g[v].size(); pt[v]++) { + int id = g[v][pt[v]]; + int to = e[id].b; + + //printf("v = %d id = %d a = %d b = %d f = %d c = %d\n", v, id, e[id].a, e[id].b, e[id].f, e[id].c); + + if (d[to] == d[v] + 1 && e[id].c - e[id].f >= flow) { + int pushed = dfs(to, flow); + if (pushed) { + e[id].f += flow; + e[id ^ 1].f -= flow; + return true; + } + } + } + return false; +} + +void dinic() { + for (lim = (1 << 30); lim >= 1;) { + if (!bfs()) { + lim >>= 1; + continue; + } + + for (int i = s; i <= t; i++) + pt[i] = 0; + + int pushed; + + while (pushed = dfs(s, lim)) { + flow = flow + lim; + } + + //cout << flow << endl; + } +} + +int main() { + //freopen("input.txt","r",stdin); + //freopen("output.txt","w",stdout); + scanf("%d %d", &n, &m); + + s = 1; t = n; + + for (int i = 1; i <= m; i++) { + int a, b, c; + scanf("%d %d %d", &a, &b, &c); + add_edge(a, b, c); + } + + dinic(); + + cout << flow << endl; + + return 0; +} diff --git a/Flow Networks & Matching/FordFulkerson.cpp b/Flow Networks & Matching/FordFulkerson.cpp new file mode 100644 index 0000000..99cf517 --- /dev/null +++ b/Flow Networks & Matching/FordFulkerson.cpp @@ -0,0 +1,104 @@ +/******************************************************************************** + + MaxFlow Ford-Fulkerson algorithm. O(M|f|), |f| - maxflow value + Based on problem 2783 from informatics.mccme.ru + http://informatics.mccme.ru/mod/statements/view3.php?chapterid=2783#1 + +********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +const int MAXN = 1050; +const int INF = (int) 1e9; + +struct edge { + int from, to, f, cap; +}; + +int n, m; +vector e; +vector g[MAXN]; +bool used[MAXN]; +int s, t; +int ans; + +void addEdge(int from, int to, int cap) { + edge ed; + + ed.from = from; ed.to = to; ed.f = 0; ed.cap = cap; + e.push_back(ed); + g[from].push_back((int) e.size() - 1); + + ed.from = to; ed.to = from; ed.f = cap; ed.cap = cap; + e.push_back(ed); + g[to].push_back((int) e.size() - 1); +} + +int pushFlow(int v, int flow = INF) { + used[v] = true; + if (v == t) + return flow; + + for (int i = 0; i < (int) g[v].size(); i++) { + int ind = g[v][i]; + int to = e[ind].to; + int f = e[ind].f; + int cap = e[ind].cap; + + if (used[to] || cap - f == 0) + continue; + + int pushed = pushFlow(to, min(flow, cap - f)); + if (pushed > 0) { + e[ind].f += pushed; + e[ind ^ 1].f -= pushed; + return pushed; + } + } + + return 0; +} + +int main() { + //assert(freopen("input.txt","r",stdin)); + //assert(freopen("output.txt","w",stdout)); + + scanf("%d %d", &n, &m); + + s = 1; t = n; + + for (int i = 1; i <= m; i++) { + int from, to, cap; + scanf("%d %d %d", &from, &to, &cap); + addEdge(from, to, cap); + } + + while (true) { + memset(used, 0, sizeof(used)); + int add = pushFlow(s); + if (add == 0) + break; + ans += add; + } + + printf("%d\n", ans); + + return 0; +} \ No newline at end of file diff --git a/Flow Networks & Matching/maxBipartiteMatching.cpp b/Flow Networks & Matching/maxBipartiteMatching.cpp new file mode 100644 index 0000000..16b24c5 --- /dev/null +++ b/Flow Networks & Matching/maxBipartiteMatching.cpp @@ -0,0 +1,41 @@ +// This code performs maximum bipartite matching. +// +// Running time: O(|E| |V|) -- often much faster in practice +// +// INPUT: w[i][j] = edge between row node i and column node j +// OUTPUT: mr[i] = assignment for row node i, -1 if unassigned +// mc[j] = assignment for column node j, -1 if unassigned +// function returns number of matches made + +#include + +using namespace std; + +typedef vector VI; +typedef vector VVI; + +bool FindMatch(int i, const VVI &w, VI &mr, VI &mc, VI &seen) { + for (int j = 0; j < w[i].size(); j++) { + if (w[i][j] && !seen[j]) { + seen[j] = true; + if (mc[j] < 0 || FindMatch(mc[j], w, mr, mc, seen)) { + mr[i] = j; + mc[j] = i; + return true; + } + } + } + return false; +} + +int BipartiteMatching(const VVI &w, VI &mr, VI &mc) { + mr = VI(w.size(), -1); + mc = VI(w[0].size(), -1); + + int ct = 0; + for (int i = 0; i < w.size(); i++) { + VI seen(w[0].size()); + if (FindMatch(i, w, mr, mc, seen)) ct++; + } + return ct; +} \ No newline at end of file diff --git a/Flow Networks & Matching/minCostMatching.cpp b/Flow Networks & Matching/minCostMatching.cpp new file mode 100644 index 0000000..a5649a2 --- /dev/null +++ b/Flow Networks & Matching/minCostMatching.cpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////// +// Min cost bipartite matching via shortest augmenting paths +// +// This is an O(n^3) implementation of a shortest augmenting path +// algorithm for finding min cost perfect matchings in dense +// graphs. In practice, it solves 1000x1000 problems in around 1 +// second. +// +// cost[i][j] = cost for pairing left node i with right node j +// Lmate[i] = index of right node that left node i pairs with +// Rmate[j] = index of left node that right node j pairs with +// +// The values in cost[i][j] may be positive or negative. To perform +// maximization, simply negate the cost[][] matrix. +/////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +using namespace std; + +typedef vector VD; +typedef vector VVD; +typedef vector VI; + +double MinCostMatching(const VVD &cost, VI &Lmate, VI &Rmate) { + int n = int(cost.size()); + + // construct dual feasible solution + VD u(n); + VD v(n); + for (int i = 0; i < n; i++) { + u[i] = cost[i][0]; + for (int j = 1; j < n; j++) u[i] = min(u[i], cost[i][j]); + } + for (int j = 0; j < n; j++) { + v[j] = cost[0][j] - u[0]; + for (int i = 1; i < n; i++) v[j] = min(v[j], cost[i][j] - u[i]); + } + + // construct primal solution satisfying complementary slackness + Lmate = VI(n, -1); + Rmate = VI(n, -1); + int mated = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (Rmate[j] != -1) continue; + if (fabs(cost[i][j] - u[i] - v[j]) < 1e-10) { + Lmate[i] = j; + Rmate[j] = i; + mated++; + break; + } + } + } + + VD dist(n); + VI dad(n); + VI seen(n); + + // repeat until primal solution is feasible + while (mated < n) { + + // find an unmatched left node + int s = 0; + while (Lmate[s] != -1) s++; + + // initialize Dijkstra + fill(dad.begin(), dad.end(), -1); + fill(seen.begin(), seen.end(), 0); + for (int k = 0; k < n; k++) + dist[k] = cost[s][k] - u[s] - v[k]; + + int j = 0; + while (true) { + + // find closest + j = -1; + for (int k = 0; k < n; k++) { + if (seen[k]) continue; + if (j == -1 || dist[k] < dist[j]) j = k; + } + seen[j] = 1; + + // termination condition + if (Rmate[j] == -1) break; + + // relax neighbors + const int i = Rmate[j]; + for (int k = 0; k < n; k++) { + if (seen[k]) continue; + const double new_dist = dist[j] + cost[i][k] - u[i] - v[k]; + if (dist[k] > new_dist) { + dist[k] = new_dist; + dad[k] = j; + } + } + } + + // update dual variables + for (int k = 0; k < n; k++) { + if (k == j || !seen[k]) continue; + const int i = Rmate[k]; + v[k] += dist[k] - dist[j]; + u[i] -= dist[k] - dist[j]; + } + u[s] += dist[j]; + + // augment along path + while (dad[j] >= 0) { + const int d = dad[j]; + Rmate[j] = Rmate[d]; + Lmate[Rmate[j]] = j; + j = d; + } + Rmate[j] = s; + Lmate[s] = j; + + mated++; + } + + double value = 0; + for (int i = 0; i < n; i++) + value += cost[i][Lmate[i]]; + + return value; +} \ No newline at end of file diff --git a/Flow Networks & Matching/minCostMaxFlow.cpp b/Flow Networks & Matching/minCostMaxFlow.cpp new file mode 100644 index 0000000..0120371 --- /dev/null +++ b/Flow Networks & Matching/minCostMaxFlow.cpp @@ -0,0 +1,100 @@ +// Implementation of min cost max flow algorithm using adjacency +// matrix (Edmonds and Karp 1972). This implementation keeps track of +// forward and reverse edges separately (so you can set cap[i][j] != +// cap[j][i]). For a regular max flow, set all edge costs to 0. +// +// Running time, O(|V|^2) cost per augmentation +// max flow: O(|V|^3) augmentations +// min cost max flow: O(|V|^4 * MAX_EDGE_COST) augmentations +// +// INPUT: +// - graph, constructed using AddEdge() +// - source +// - sink +// +// OUTPUT: +// - (maximum flow value, minimum cost value) +// - To obtain the actual flow, look at positive values only. + +#include +#include +#include + +using namespace std; + +typedef vector VI; +typedef vector VVI; +typedef long long L; +typedef vector VL; +typedef vector VVL; +typedef pair PII; +typedef vector VPII; + +const L INF = numeric_limits::max() / 4; + +struct MinCostMaxFlow { + int N; + VVL cap, flow, cost; + VI found; + VL dist, pi, width; + VPII dad; + + MinCostMaxFlow(int N) : + N(N), cap(N, VL(N)), flow(N, VL(N)), cost(N, VL(N)), + found(N), dist(N), pi(N), width(N), dad(N) {} + + void AddEdge(int from, int to, L cap, L cost) { + this->cap[from][to] = cap; + this->cost[from][to] = cost; + } + + void Relax(int s, int k, L cap, L cost, int dir) { + L val = dist[s] + pi[s] - pi[k] + cost; + if (cap && val < dist[k]) { + dist[k] = val; + dad[k] = make_pair(s, dir); + width[k] = min(cap, width[s]); + } + } + + L Dijkstra(int s, int t) { + fill(found.begin(), found.end(), false); + fill(dist.begin(), dist.end(), INF); + fill(width.begin(), width.end(), 0); + dist[s] = 0; + width[s] = INF; + + while (s != -1) { + int best = -1; + found[s] = true; + for (int k = 0; k < N; k++) { + if (found[k]) continue; + Relax(s, k, cap[s][k] - flow[s][k], cost[s][k], 1); + Relax(s, k, flow[k][s], -cost[k][s], -1); + if (best == -1 || dist[k] < dist[best]) best = k; + } + s = best; + } + + for (int k = 0; k < N; k++) + pi[k] = min(pi[k] + dist[k], INF); + return width[t]; + } + + pair GetMaxFlow(int s, int t) { + L totflow = 0, totcost = 0; + while (L amt = Dijkstra(s, t)) { + totflow += amt; + for (int x = t; x != s; x = dad[x].first) { + if (dad[x].second == 1) { + flow[dad[x].first][x] += amt; + totcost += amt * cost[dad[x].first][x]; + } else { + flow[x][dad[x].first] -= amt; + totcost -= amt * cost[x][dad[x].first]; + } + } + } + return make_pair(totflow, totcost); + } +}; \ No newline at end of file diff --git a/Flow Networks & Matching/minCut.cpp b/Flow Networks & Matching/minCut.cpp new file mode 100644 index 0000000..42166d0 --- /dev/null +++ b/Flow Networks & Matching/minCut.cpp @@ -0,0 +1,54 @@ +// Adjacency matrix implementation of Stoer-Wagner min cut algorithm. +// +// Running time: +// O(|V|^3) +// +// INPUT: +// - graph, constructed using AddEdge() +// +// OUTPUT: +// - (min cut value, nodes in half of min cut) + +#include +#include +#include + +using namespace std; + +typedef vector VI; +typedef vector VVI; + +const int INF = 1000000000; + +pair GetMinCut(VVI &weights) { + int N = weights.size(); + VI used(N), cut, best_cut; + int best_weight = -1; + + for (int phase = N - 1; phase >= 0; phase--) { + VI w = weights[0]; + VI added = used; + int prev, last = 0; + for (int i = 0; i < phase; i++) { + prev = last; + last = -1; + for (int j = 1; j < N; j++) + if (!added[j] && (last == -1 || w[j] > w[last])) last = j; + if (i == phase - 1) { + for (int j = 0; j < N; j++) weights[prev][j] += weights[last][j]; + for (int j = 0; j < N; j++) weights[j][prev] = weights[prev][j]; + used[last] = true; + cut.push_back(last); + if (best_weight == -1 || w[last] < best_weight) { + best_cut = cut; + best_weight = w[last]; + } + } else { + for (int j = 0; j < N; j++) + w[j] += weights[last][j]; + added[last] = true; + } + } + } + return make_pair(best_weight, best_cut); +} \ No newline at end of file diff --git a/Flow Networks & Matching/pushRelabel.cpp b/Flow Networks & Matching/pushRelabel.cpp new file mode 100644 index 0000000..a0f2519 --- /dev/null +++ b/Flow Networks & Matching/pushRelabel.cpp @@ -0,0 +1,116 @@ +// Adjacency list implementation of FIFO push relabel maximum flow +// with the gap relabeling heuristic. This implementation is +// significantly faster than straight Ford-Fulkerson. It solves +// random problems with 10000 vertices and 1000000 edges in a few +// seconds, though it is possible to construct test cases that +// achieve the worst-case. +// +// Running time: +// O(|V|^3) +// +// INPUT: +// - graph, constructed using AddEdge() +// - source +// - sink +// +// OUTPUT: +// - maximum flow value +// - To obtain the actual flow values, look at all edges with +// capacity > 0 (zero capacity edges are residual edges). + +#include +#include +#include +#include + +using namespace std; + +typedef long long LL; + +struct Edge { + int from, to, cap, flow, index; + Edge(int from, int to, int cap, int flow, int index) : + from(from), to(to), cap(cap), flow(flow), index(index) {} +}; + +struct PushRelabel { + int N; + vector > G; + vector excess; + vector dist, active, count; + queue Q; + + PushRelabel(int N) : N(N), G(N), excess(N), dist(N), active(N), count(2 * N) {} + + void AddEdge(int from, int to, int cap) { + G[from].push_back(Edge(from, to, cap, 0, G[to].size())); + if (from == to) G[from].back().index++; + G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1)); + } + + void Enqueue(int v) { + if (!active[v] && excess[v] > 0) { active[v] = true; Q.push(v); } + } + + void Push(Edge &e) { + int amt = int(min(excess[e.from], LL(e.cap - e.flow))); + if (dist[e.from] <= dist[e.to] || amt == 0) return; + e.flow += amt; + G[e.to][e.index].flow -= amt; + excess[e.to] += amt; + excess[e.from] -= amt; + Enqueue(e.to); + } + + void Gap(int k) { + 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); + } + } + + void Relabel(int v) { + count[dist[v]]--; + dist[v] = 2 * N; + for (int i = 0; i < G[v].size(); i++) + if (G[v][i].cap - G[v][i].flow > 0) + dist[v] = min(dist[v], dist[G[v][i].to] + 1); + count[dist[v]]++; + Enqueue(v); + } + + void Discharge(int v) { + for (int i = 0; excess[v] > 0 && i < G[v].size(); i++) Push(G[v][i]); + if (excess[v] > 0) { + if (count[dist[v]] == 1) + Gap(dist[v]); + else + Relabel(v); + } + } + + LL GetMaxFlow(int s, int t) { + count[0] = N - 1; + count[N] = 1; + dist[s] = N; + active[s] = active[t] = true; + for (int i = 0; i < G[s].size(); i++) { + excess[s] += G[s][i].cap; + Push(G[s][i]); + } + + while (!Q.empty()) { + int v = Q.front(); + Q.pop(); + active[v] = false; + Discharge(v); + } + + LL totflow = 0; + for (int i = 0; i < G[s].size(); i++) totflow += G[s][i].flow; + return totflow; + } +}; \ No newline at end of file From a440bce9b9b257dfd04ed700a993e3d9d824ecfb Mon Sep 17 00:00:00 2001 From: Akul Mehra Date: Sat, 10 Oct 2015 19:28:31 +0530 Subject: [PATCH 6/9] misc --- Computational Geometry/pick_theorem.cpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Computational Geometry/pick_theorem.cpp diff --git a/Computational Geometry/pick_theorem.cpp b/Computational Geometry/pick_theorem.cpp new file mode 100644 index 0000000..3abf169 --- /dev/null +++ b/Computational Geometry/pick_theorem.cpp @@ -0,0 +1,2 @@ +On a simple polygon constructed on a grid of equal - distanced points, for area A, +number of interior points I, number of boundary points B, we have A = I + B / 2 - 1. \ No newline at end of file From 6663bda7ef03f664c2a0ddbe65f3badd7f1fc5d0 Mon Sep 17 00:00:00 2001 From: Akul Mehra Date: Sat, 10 Oct 2015 19:29:11 +0530 Subject: [PATCH 7/9] misc --- Data Structures/advance_binary_index_tree.cpp | 117 ++++++++++++++++++ Data Structures/binary_index_tree.cpp | 52 ++++++++ Maths (Probablitiy, Algebra, ..)/README.md | 3 +- Maths (Probablitiy, Algebra, ..)/binomial.cpp | 9 ++ .../catalan_number.cpp | 3 + .../chinese_remainder.cpp | 15 +++ .../combinatorial_game_theory.cpp | 10 ++ .../euler_totient.cpp | 20 +++ .../gaussian_elimination.cpp | 97 +++++++++++++++ .../great_common_divisor.cpp | 11 ++ .../kirchoff_theorem.cpp | 17 +++ .../lucas_theorem.cpp | 38 ++++++ .../matrix_determinants.cpp | 30 +++++ .../matrix_inverse.cpp | 49 ++++++++ .../modular_inverse.cpp | 6 + .../modular_matrix_inverse.cpp | 47 +++++++ .../modular_power.cpp | 17 +++ Maths (Probablitiy, Algebra, ..)/simplex.cpp | 99 +++++++++++++++ String Algorithms/kmp.cpp | 37 ++++++ String Algorithms/suffix_array.cpp | 94 ++++++++++++++ String Algorithms/suffix_with_lcp.cpp | 53 ++++++++ 21 files changed, 823 insertions(+), 1 deletion(-) create mode 100644 Data Structures/advance_binary_index_tree.cpp create mode 100644 Data Structures/binary_index_tree.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/binomial.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/catalan_number.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/chinese_remainder.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/combinatorial_game_theory.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/euler_totient.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/gaussian_elimination.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/great_common_divisor.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/kirchoff_theorem.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/lucas_theorem.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/matrix_determinants.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/matrix_inverse.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/modular_inverse.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/modular_matrix_inverse.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/modular_power.cpp create mode 100644 Maths (Probablitiy, Algebra, ..)/simplex.cpp create mode 100644 String Algorithms/kmp.cpp create mode 100644 String Algorithms/suffix_array.cpp create mode 100644 String Algorithms/suffix_with_lcp.cpp diff --git a/Data Structures/advance_binary_index_tree.cpp b/Data Structures/advance_binary_index_tree.cpp new file mode 100644 index 0000000..0c5a85d --- /dev/null +++ b/Data Structures/advance_binary_index_tree.cpp @@ -0,0 +1,117 @@ +itree::init(); +itree::update(s, e, val); // [s, e] 구간의 값을 val +로 업데이트 +val = itree::getrange(s, e); // [s, e] 구간의 대표값 +#include +using namespace std; +namespace itree { +typedef int val_t; +const int size = 1024; // 2 +의 제곱수여야 +함 +// 트리를 초기화할 +값 +// +예) 구간 최소: 0x7fFFffFF +// 구간합: 0 +const val_t init_value = 0; +// 내부노드 갱신을 위해 가중치를 계산하는 함수 +// +예) 구간 최소 +/ 최대: return a; +// 구간 +합: return a * len; +inline val_t weight(val_t a, int len) { + return a * len; + Seoul National University 22 +} +// 트리의 두 child를 병합하는 함수 +// 예) 구간 최소: return min(a, b); +// 구간합: return a + b; +val_t sum(val_t a, val_t b) { + return a + b; +} +// 노드의 구간 대표값: 두 child를 병합한 값 a와, 자신에게 할당된 값 b를 병합 +// 예) 구간 최소: return min(a, b); +// 구간합: return a + b; +val_t update_a(val_t a, val_t b) { + return a + b; +} +// 노드의 구간 대표값: 기존의 구간 대표값 b1과, 새로운 값 b2를 병합 +val_t update_b(val_t b1, val_t b2) { + return b1 + b2; +} +pair itree[size * 2]; +pair ptree[size * 2]; +void init() { + int i; + for (i = 1 ; i < size * 2 ; i++) + itree[i] = make_pair(init_value, init_value); + for (i = size ; i < size * 2 ; i++) + ptree[i] = make_pair(i, i); + for (i = size - 1 ; i >= 1 ; i--) + ptree[i] = make_pair(ptree[i << 1].first, ptree[i << 1 | 1].second); +} +void update(int s, int e, val_t val) { // [s, e] + int s1, e1; + int d = 0; + s |= size; + e |= size; + s1 = s >> 1; + e1 = e >> 1; + while (s <= e) { + if (s & 1) { + itree[s].second = update_b(itree[s].second, val); + val_t child_sum = sum(itree[s << 1].first, itree[s << 1 | 1].first); + itree[s].first = update_a( + (s >= size) ? init_value : child_sum, + weight(itree[s].second, 1 << d)); + } + if ((e & 1) == 0) { + itree[e].second = update_b(itree[e].second, val); + val_t child_sum = sum(itree[e << 1].first, itree[e << 1 | 1].first); + itree[e].first = update_a( + (e >= size) ? init_value : child_sum, + weight(itree[e].second, 1 << d)); + } + s = (s + 1) >> 1; + e = (e - 1) >> 1; + d++; + } + d = 1; + while (s1) { + itree[s1].first = update_a( + sum(itree[s1 << 1].first, itree[s1 << 1 | 1].first), + weight(itree[s1].second, 1 << d)); + itree[e1].first = update_a( + sum(itree[e1 << 1].first, itree[e1 << 1 | 1].first), + weight(itree[e1].second, 1 << d)); + s1 >>= 1; + e1 >>= 1; + d++; + } +} +val_t _getrange2(int s, int e, int node) { + if (node >= size) + return itree[node].first; + if (s <= ptree[node].first && e >= ptree[node].second) + return itree[node].first; + val_t cur = weight(itree[node].second, + min(e, ptree[node].second) - max(s, ptree[node].first) + 1); + int left = node << 1; + int right = node << 1 | 1; + if (s >= ptree[right].first) + return update_a(_getrange2(s, e, right), cur); + else if (e <= ptree[left].second) + Seoul National University 23 + return update_a(_getrange2(s, e, left), cur); + else + return update_a( + sum(_getrange2(s, e, left), _getrange2(s, e, right)), + cur); +} +val_t getrange(int s, int e) { // [s, e] + if (s > e) return init_value; + return _getrange2(s | size, e | size, 1); +} +} // namespace itree \ No newline at end of file diff --git a/Data Structures/binary_index_tree.cpp b/Data Structures/binary_index_tree.cpp new file mode 100644 index 0000000..e8963f6 --- /dev/null +++ b/Data Structures/binary_index_tree.cpp @@ -0,0 +1,52 @@ +itree::init(); +itree::update(pos, val); // pos 위치를 val +로 업데이트 +val = itree::getrange(s, e); // [s, e] 구간의 대표값 +namespace itree { +typedef int val_t; +const int size = 16384; // 2 +의 제곱수여야 +함 +// 트리를 초기화할 +값 +// +예) 구간 최소: 0x7fFFffFF +// 구간합: 0 +const val_t init_value = 0; +// 트리의 +두 child +를 병합하는 함수 +// +예) 구간 최소: return min(a, b); +// 구간합: return a + b; +val_t sum(val_t a, val_t b) { + return a + b; +} +val_t itree[size * 2 + 1]; +void init() { + for (int i = 1 ; i <= size * 2 ; i++) + itree[i] = init_value; +} +void update(int pos, val_t val) { + pos |= size; + itree[pos] = val; + while (pos >>= 1) + itree[pos] = sum(itree[pos << 1], itree[pos << 1 | 1]); +} +val_t getrange(int s, int e) { // [s, e] + val_t ret = init_value; + s |= size; + e |= size; + while (s <= e) { + if (s & 1) + ret = sum(ret, itree[s]); + if ((e & 1) == 0) + ret = sum(ret, itree[e]); + s = (s + 1) >> 1; + e = (e + - 1) >> 1; + + } + return ret; +} +} // namespace itree \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/README.md b/Maths (Probablitiy, Algebra, ..)/README.md index 3b37685..5047a8b 100644 --- a/Maths (Probablitiy, Algebra, ..)/README.md +++ b/Maths (Probablitiy, Algebra, ..)/README.md @@ -187,4 +187,5 @@ of a polynomial ] - Suggested Reading - Herbert Wilf's generating functionology - - Robert Sedgewick and Flajoulet's Combinatorial analysis \ No newline at end of file + - Robert Sedgewick and Flajoulet's Combinatorial analysis + diff --git a/Maths (Probablitiy, Algebra, ..)/binomial.cpp b/Maths (Probablitiy, Algebra, ..)/binomial.cpp new file mode 100644 index 0000000..3707fcf --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/binomial.cpp @@ -0,0 +1,9 @@ +long long binomial(int n, int m) { + if (n > m || n < 0) return 0; + long long ans = 1, ans2 = 1; + for (int i = 0 ; i < m ; i++) { + ans *= n - i; + ans2 *= i + 1; + } + return ans / ans2; +} diff --git a/Maths (Probablitiy, Algebra, ..)/catalan_number.cpp b/Maths (Probablitiy, Algebra, ..)/catalan_number.cpp new file mode 100644 index 0000000..b6d35c6 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/catalan_number.cpp @@ -0,0 +1,3 @@ +long long catalan_number(int n) { + return binomial(n * 2, n) / (n + 1); +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/chinese_remainder.cpp b/Maths (Probablitiy, Algebra, ..)/chinese_remainder.cpp new file mode 100644 index 0000000..d9d6c14 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/chinese_remainder.cpp @@ -0,0 +1,15 @@ +//x = a (mod n)가 되는 x를 찾는다. + // Dependencies: gcd(a, b), modinverse(a, m) +long long chinese_remainder(long long *a, long long *n, int size) { + if (size == 1) return *a; + long long tmp = modinverse(n[0], n[1]); + long long tmp2 = (tmp * (a[1] - a[0]) % n[1] + n[1]) % n[1]; + long long ora = a[1]; + long long tgcd = gcd(n[0], n[1]); + a[1] = a[0] + n[0] / tgcd * tmp2; + n[1] *= n[0] / tgcd; + long long ret = chinese_remainder(a + 1, n + 1, size - 1); + n[1] /= n[0] / tgcd; + a[1] = ora; + return ret; +} diff --git a/Maths (Probablitiy, Algebra, ..)/combinatorial_game_theory.cpp b/Maths (Probablitiy, Algebra, ..)/combinatorial_game_theory.cpp new file mode 100644 index 0000000..0a1ec17 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/combinatorial_game_theory.cpp @@ -0,0 +1,10 @@ +game sum: A xor B +game calc: minimum excluded number { Possible Games } +staircase nim: 짝수 계단에 있는 것들은 전부 소용 없음. 누구든 원래 nim 상태로 복귀시킬 +수 있다. +Moore's nim_k: k개씩 제거하는 nim. 2진수로 변환하고, k+1진수에서 xor 하듯이 carry 없 +이 더한다. +misere nim: play exactly as if you were playing normal play nim, except if your +winning move would lead to a position that consists of heaps of size one only. +In that case, leave exactly one more or one fewer heaps of size one than the +normal play strategy recommends. \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/euler_totient.cpp b/Maths (Probablitiy, Algebra, ..)/euler_totient.cpp new file mode 100644 index 0000000..855f431 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/euler_totient.cpp @@ -0,0 +1,20 @@ +phi(n), n 이하의 양수 중 n과 서로 소인 것의 개수를 구한다. +Dependencies: - +// phi(n) = (p_1 - 1) * p_1 ^ (k_1 - 1) * (p_2 - 1) * p_2 ^ (k_2-1) +long long euler_totient2(long long n, long long ps) { + for (long long i = ps ; i * i <= n ; i++) { + if (n % i == 0) { + long long p = 1; + while (n % i == 0) { + n /= i; + p *= i; + } + return (p - p / i) * euler_totient2(n, i + 1); + } + if (i > 2) i++; + } + return n - 1; +} +long long euler_totient(long long n) { + return euler_totient2(n, 2); +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/gaussian_elimination.cpp b/Maths (Probablitiy, Algebra, ..)/gaussian_elimination.cpp new file mode 100644 index 0000000..b9fcfd1 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/gaussian_elimination.cpp @@ -0,0 +1,97 @@ +gaussian::run(size_eq, size_var, A, B, C); +A는 1차원 배열의 꼴로 주어지는 2차원 행렬이다. 배열 C의 값을 채워 넣는 루틴은 별도로 +구현하라. val_t로 double을 사용할 경우 abs 함수의 구현을 적절히 수정하라. +#include +using namespace std; +long long gcd(long long a, long long b) +{ + if (b == 0) + return a; + return gcd(b, a % b); +} +struct rational { + long long p, q; + void red() { + if (q < 0) { + p *= -1; + q *= -1; + } + long long t = gcd((p >= 0 ? p : -p), q); + p /= t; + q /= t; + } + rational() {} + rational(long long p_): p(p_), q(1) {} + rational(long long p_, long long q_): p(p_), q(q_) { red(); } + bool operator==(const rational& rhs) const { + return p == rhs.p && q == rhs.q; + } + bool operator!=(const rational& rhs) const { + return p != rhs.p || q != rhs.q; + } + bool operator<(const rational& rhs) const { + return p * rhs.q < rhs.p * q; + } + const rational operator+(const rational& rhs) const { + return rational(p * rhs.q + q * rhs.p, q * rhs.q); + } + const rational operator-(const rational& rhs) const { + return rational(p * rhs.q - q * rhs.p, q * rhs.q); + } + const rational operator*(const rational& rhs) const { + return rational(p * rhs.p, q * rhs.q); + } + const rational operator/(const rational& rhs) const { + return rational(p * rhs.q, q * rhs.p); + } +}; +namespace gaussian +{ +Seoul National University 16 +typedef rational val_t; +const val_t abs(const val_t& x) { + return (x.p >= 0) ? x : rational(-x.p, x.q); +} +#define GET(i, j, n) A[i * n + j] +// return true when solution exists, false o/w. +bool run(int size_eq, int size_var, val_t* A, val_t* B, val_t* C) { + int i = 0, j = 0, k, l; + int maxi; + val_t temp_r; + val_t* x; + val_t* y; + while (i < size_eq && j < size_var) { + maxi = i; + for (k = i + 1 ; k < size_eq ; k++) + if (abs(GET(maxi, j, size_var)) < abs(GET(k, j, size_var))) + maxi = k; + if (GET(maxi, j, size_var) != val_t(0)) { + x = A + i * size_var; + y = A + maxi * size_var; + for (k = 0 ; k < size_var ; k++) + swap(*(x + k), *(y + k)); + swap(B[i], B[maxi]); + temp_r = *(x + j); + for (k = j ; k < size_var ; k++) + *(x + k) = *(x + k) / temp_r; + B[i] = B[i] / temp_r; + for (k = 0 ; k < size_eq ; k++) { + if (k == i) continue; + temp_r = GET(k, j, size_var); + for (l = j ; l < size_var ; l++) + GET(k, l, size_var) = GET(k, l, size_var) + - temp_r * GET(i, l, size_var); + B[k] = B[k] - GET(k, j, size_var) * B[i]; + } + i++; + } + j++; + } + if (i < size_eq) + for ( ; i < size_eq ; i++) + if (B[i] != val_t(0)) return false; +// C[...] := Case by case + return true; +} +#undef GET +} // namespace gaussian diff --git a/Maths (Probablitiy, Algebra, ..)/great_common_divisor.cpp b/Maths (Probablitiy, Algebra, ..)/great_common_divisor.cpp new file mode 100644 index 0000000..61346aa --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/great_common_divisor.cpp @@ -0,0 +1,11 @@ +long long gcd(long long a, long long b) { + if (b == 0) return a; + return gcd(b, a % b); +} +//Extended GCD +//ac + bd = gcd(a, b)가 되는 (c, d)를 찾는다. +pair extended_gcd(long long a, long long b) { + if (b == 0) return make_pair(1, 0); + pair t = extended_gcd(b, a % b); + return make_pair(t.second, t.first - t.second * (a / b)); +} diff --git a/Maths (Probablitiy, Algebra, ..)/kirchoff_theorem.cpp b/Maths (Probablitiy, Algebra, ..)/kirchoff_theorem.cpp new file mode 100644 index 0000000..8d45451 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/kirchoff_theorem.cpp @@ -0,0 +1,17 @@ +//Dependencies: mat_det(matrix, n) +long long count_spantree(vector graph[], int size) { + int i, j; + vector > matrix(size - 1); + for (i = 0 ; i < size - 1 ; i++) { + matrix[i].resize(size - 1); + for (j = 0 ; j < size - 1 ; j++) + matrix[i][j] = 0; + for (j = 0 ; j < graph[i].size() ; j++) { + if (graph[i][j] < size - 1) { + matrix[i][graph[i][j]]--; + matrix[i][i]++; + } + } + } + return (long long)(mat_det(matrix, size - 1) + 0.5); +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/lucas_theorem.cpp b/Maths (Probablitiy, Algebra, ..)/lucas_theorem.cpp new file mode 100644 index 0000000..37fdef8 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/lucas_theorem.cpp @@ -0,0 +1,38 @@ +//nCm mod p의 값을 구한다. +//Dependencies: binomial(n, m) +int lucas_theorem(const char *n, const char *m, int p) { + vector np, mp; + int i; + for (i = 0 ; n[i] ; i++) { + if (n[i] == '0' && np.empty()) continue; + np.push_back(n[i] - '0'); + } + for (i = 0 ; m[i] ; i++) { + if (m[i] == '0' && mp.empty()) continue; + mp.push_back(m[i] - '0'); + Seoul National University 13 + } + int ret = 1; + int ni = 0, mi = 0; + while (ni < np.size() || mi < mp.size()) { + int nmod = 0, mmod = 0; + for (i = ni ; i < np.size() ; i++) { + if (i + 1 < np.size()) + np[i + 1] += (np[i] % p) * 10; + else + nmod = np[i] % p; + np[i] /= p; + } + for (i = mi ; i < mp.size() ; i++) { + if (i + 1 < mp.size()) + mp[i + 1] += (mp[i] % p) * 10; + else + mmod = mp[i] % p; + mp[i] /= p; + } + while (ni < np.size() && np[ni] == 0) ni++; + while (mi < mp.size() && mp[mi] == 0) mi++; + ret = (ret * binomial(nmod, mmod)) % p; + } + return ret; +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/matrix_determinants.cpp b/Maths (Probablitiy, Algebra, ..)/matrix_determinants.cpp new file mode 100644 index 0000000..75564e3 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/matrix_determinants.cpp @@ -0,0 +1,30 @@ +//Dependencies: - +double mat_det(vector > matrix, int n) { + int i, j, k; + double ret = 1; + for (i = 0 ; i < n ; i++) { + if (eq(matrix[i][i], 0)) { + for (j = i + 1 ; j < n ; j++) { + if (!eq(matrix[j][i], 0)) { + for (k = 0 ; k < n ; k++) + matrix[i][k] += matrix[j][k]; + break; + } + } + if (j == n) + return 0; + } + double tmp = matrix[i][i]; + for (k = 0 ; k < n ; k++) + matrix[i][k] /= tmp; + Seoul National University 15 + ret *= tmp; + for (j = 0 ; j < n ; j++) { + if (j == i) continue; + tmp = matrix[j][i]; + for (k = 0 ; k < n ; k++) + matrix[j][k] -= matrix[i][k] * tmp; + } + } + return ret; +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/matrix_inverse.cpp b/Maths (Probablitiy, Algebra, ..)/matrix_inverse.cpp new file mode 100644 index 0000000..6ffdaa3 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/matrix_inverse.cpp @@ -0,0 +1,49 @@ +Dependencies: - +inline bool eq(double a, double b) { + static const double eps = 1e-9; + return fabs(a - b) < eps; +} +// returns empty vector if fails +vector > mat_inverse(vector > matrix, int n) { + int i, j, k; + vector > ret; + ret.resize(n); + for (i = 0 ; i < n ; i++) { + ret[i].resize(n); + for (j = 0 ; j < n ; j++) + ret[i][j] = 0; + ret[i][i] = 1; + } + for (i = 0 ; i < n ; i++) { + if (eq(matrix[i][i], 0)) { + for (j = i + 1 ; j < n ; j++) { + if (!eq(matrix[j][i], 0)) { + for (k = 0 ; k < n ; k++) { + matrix[i][k] += matrix[j][k]; + ret[i][k] += ret[j][k]; + } + break; + } + } + if (j == n) { + ret.clear(); + return ret; + Seoul National University 14 + } + } + double tmp = matrix[i][i]; + for (k = 0 ; k < n ; k++) { + matrix[i][k] /= tmp; + ret[i][k] /= tmp; + } + for (j = 0 ; j < n ; j++) { + if (j == i) continue; + tmp = matrix[j][i]; + for (k = 0 ; k < n ; k++) { + matrix[j][k] -= matrix[i][k] * tmp; + ret[j][k] -= ret[i][k] * tmp; + } + } + } + return ret; +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/modular_inverse.cpp b/Maths (Probablitiy, Algebra, ..)/modular_inverse.cpp new file mode 100644 index 0000000..7b1df67 --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/modular_inverse.cpp @@ -0,0 +1,6 @@ +//Modular Inverse +ax = gcd(a, m) (mod m)가 되는 x를 찾는다. + //Dependencies: extended_gcd(a, b) +long long modinverse(long long a, long long m) { + return (extended_gcd(a, m).first % m + m) % m; +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/modular_matrix_inverse.cpp b/Maths (Probablitiy, Algebra, ..)/modular_matrix_inverse.cpp new file mode 100644 index 0000000..7151b2a --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/modular_matrix_inverse.cpp @@ -0,0 +1,47 @@ +//Dependencies: modinverse(a, m) +// returns empty vector if fails +vector > mat_inverse(vector > matrix, int n, + long long mod) { + int i, j, k; + vector > ret; + ret.resize(n); + for (i = 0 ; i < n ; i++) { + ret[i].resize(n); + for (j = 0 ; j < n ; j++) + ret[i][j] = 0; + ret[i][i] = 1 % mod; + } + for (i = 0 ; i < n ; i++) { + if (matrix[i][i] == 0) { + for (j = i + 1 ; j < n ; j++) { + if (matrix[j][i] != 0) { + for (k = 0 ; k < n ; k++) { + matrix[i][k] = (matrix[i][k] + matrix[j][k]) % mod; + ret[i][k] = (ret[i][k] + ret[j][k]) % mod; + } + break; + } + } + if (j == n) { + ret.clear(); + return ret; + } + } + long long tmp = modinverse(matrix[i][i], mod); + for (k = 0 ; k < n ; k++) { + matrix[i][k] = (matrix[i][k] * tmp) % mod; + ret[i][k] = (ret[i][k] * tmp) % mod; + } + for (j = 0 ; j < n ; j++) { + if (j == i) continue; + tmp = matrix[j][i]; + for (k = 0 ; k < n ; k++) { + matrix[j][k] -= matrix[i][k] * tmp; + matrix[j][k] = (matrix[j][k] % mod + mod) % mod; + ret[j][k] -= ret[i][k] * tmp; + ret[j][k] = (ret[j][k] % mod + mod) % mod; + } + } + } + return ret; +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/modular_power.cpp b/Maths (Probablitiy, Algebra, ..)/modular_power.cpp new file mode 100644 index 0000000..d0be94a --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/modular_power.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include +using namespace std; +//Modular Power +//n^k mod m + +long long power(long long n, long long k, long long m = LLONG_MAX) { + long long ret = 1; + while (k) { + if (k & 1) ret = (ret * n) % m; + n = (n * n) % m; + k >>= 1; + } + return ret; +} \ No newline at end of file diff --git a/Maths (Probablitiy, Algebra, ..)/simplex.cpp b/Maths (Probablitiy, Algebra, ..)/simplex.cpp new file mode 100644 index 0000000..716063b --- /dev/null +++ b/Maths (Probablitiy, Algebra, ..)/simplex.cpp @@ -0,0 +1,99 @@ +Simplex Algorithm +n : = number of constraints + m : = number of variables + matrix[0] : = maximize할 식의 계수 + matrix[1~n] : = constraints + solution : = results + solution[n] : = 원하는 식의 최대값 + 부등식의 우변(변수 없는 쪽)이 음이 아닌 수가 되도록 정리하여 대입한다. + ex) Maximize p = -2x + 3y + Constraints: x + 3y ≤ 40 + 2x + 4y ≥ 10 + x ≥ 0, y ≥ 0 + n = 2, m = 2, matrix = [ 2 - 3 1 0 0 ] , c = [ 0 ] + [ 1 3 0 1 0 ] [ 40 ] + [ 2 4 0 0 - 1 ] [ 10 ] + namespace simplex +{ +const int MAX_N = 50; +const int MAX_M = 50; +const double eps = 1e-9; +inline int diff(double a, double b) { + if (a - eps < b && b < a + eps) return 0; + return (a < b) ? -1 : 1; +} +int n, m; +double matrix[MAX_N + 1][MAX_M + MAX_N + 1]; +double c[MAX_N + 1]; +double solution[MAX_M + MAX_N + 1]; +int simplex() { // 0: found solution, 1: no feasible solution, 2: unbounded + int i, j; + while (true) { + int nonfeasible = -1; + for (j = 0 ; j <= n + m ; j++) { + Seoul National University 17 + int cnt = 0, pos = -1; + for (i = 0 ; i <= n ; i++) { + if (diff(matrix[i][j], 0)) { + cnt++; + pos = i; + } + } + if (cnt != 1) + solution[j] = 0; + else { + solution[j] = c[pos] / matrix[pos][j]; + if (solution[j] < 0) nonfeasible = i; + } + } + int pivotcol = -1; + if (nonfeasible != -1) { + double maxv = 0; + for (j = 0 ; j <= n + m ; j++) { + if (maxv < matrix[nonfeasible][j]) { + maxv = matrix[nonfeasible][j]; + pivotcol = j; + } + } + if (pivotcol == -1) return 1; + } + else { + double minv = 0; + for (j = 0 ; j <= n + m ; j++) { + if (minv > matrix[0][j]) { + minv = matrix[0][j]; + pivotcol = j; + } + } + if (pivotcol == -1) return 0; + } + double minv = -1; + int pivotrow = -1; + for (i = 0 ; i <= n ; i++) { + if (diff(matrix[i][pivotcol], 0) > 0) { + double test = c[i] / matrix[i][pivotcol]; + if (test < minv || minv < 0) { + minv = test; + pivotrow = i; + } + } + } + if (pivotrow == -1) return 2; + for (i = 0 ; i <= n ; i++) { + if (i == pivotrow) continue; + if (diff(matrix[i][pivotcol], 0)) { + double ratio = matrix[i][pivotcol] / matrix[pivotrow][pivotcol]; + for (j = 0 ; j <= n + m ; j++) { + if (j == pivotcol) { + matrix[i][j] = 0; + continue; + } + else + matrix[i][j] -= ratio * matrix[pivotrow][j]; + } + c[i] -= ratio * c[pivotrow]; + } + } + } +} +} // namespace simplex \ No newline at end of file diff --git a/String Algorithms/kmp.cpp b/String Algorithms/kmp.cpp new file mode 100644 index 0000000..297db6e --- /dev/null +++ b/String Algorithms/kmp.cpp @@ -0,0 +1,37 @@ +result = kmp::match(text, pattern); // 모든 matched point의 vector +#include +using namespace std; +namespace kmp +{ +typedef vector seq_t; +void calculate_pi(vector& pi, const seq_t& str) { + pi[0] = -1; + int j = -1; + for (int i = 1 ; i < str.size() ; i++) { + while (j >= 0 && str[i] != str[j + 1]) j = pi[j]; + if (str[i] == str[j + 1]) + pi[i] = ++j; + else + pi[i] = -1; + } +} +/* returns all positions matched */ +vector match(seq_t text, seq_t pattern) { + vector pi(pattern.size()); + vector ans; + if (pattern.size() == 0) return ans; + calculate_pi(pi, pattern); + int j = -1; + for (int i = 0 ; i < text.size() ; i++) { + while (j >= 0 && text[i] != pattern[j + 1]) j = pi[j]; + if (text[i] == pattern[j + 1]) { + j++; + if (j + 1 == pattern.size()) { + ans.push_back(i - j); + j = pi[j]; + } + } + } + return ans; +} +} // namespace kmp \ No newline at end of file diff --git a/String Algorithms/suffix_array.cpp b/String Algorithms/suffix_array.cpp new file mode 100644 index 0000000..17d069d --- /dev/null +++ b/String Algorithms/suffix_array.cpp @@ -0,0 +1,94 @@ +Suffix Array O(n log n) +#include +#include +using namespace std; +int n, K; +int dat[20003]; +int ians[20003]; // ans -> index : 답의 반대 +int ans[20003]; // index -> ans : 구하고자 하는 suffix array +int tmpans[20003]; // ans의 중간과정 저장 +int bucket[20003]; // bucket -> index : starting points +int bucketcnt[20003]; // bucket -> count +int cntbucket; // number of buckets +int bucketmark[20003]; // ans -> bucket : 어느 bucket에 속하는가? +int bucketupdate[20003]; // ans -> bucketnumber. -1이면 새 거. +inline int sf(const int& a, const int& b) { + return dat[a] < dat[b]; +} +int main() { + int i, H; + scanf("%d%d", &n, &K); + for (i = 0 ; i < n ; i++) { + scanf("%d", &dat[i]); + dat[i]++; + ans[i] = i; + ians[i] = i; + Seoul National University 24 + } +// constructing suffix array by doubling method +// phase 1: init + sort(ans, ans + n, sf); + for (i = 0 ; i < n ; i++) { + if (i == 0 || dat[ans[i]] != dat[ans[i - 1]]) { + bucket[cntbucket] = i; + bucketcnt[cntbucket] = 0; + cntbucket++; + } + bucketmark[ans[i]] = cntbucket - 1; + } +// phase 2: doubling + for (H = 1 ; ; H *= 2) { +// phase 2-1: rearrangement +// 현재 위치의 H만큼 뒤를 보면서 위치를 바꿈, 결과를 tmpans에 저장 + for (i = 0 ; i < n ; i++) { + if (ans[i] >= n - H) { +// 이 뒤는 null 문자이므로 앞으로 가야 한다. + int tbuck = bucketmark[ans[i]]; + bucketupdate[ans[i]] = -1; + tmpans[bucket[tbuck] + bucketcnt[tbuck]] = ans[i]; + bucketcnt[tbuck]++; + } + } + for (i = 0 ; i < n ; i++) { + if (ans[i] >= H) { +// 위에서 처리하지 않은 나머지 것들 + int tbuck = bucketmark[ans[i] - H]; + bucketupdate[ans[i] - H] = bucketmark[ans[i]]; + tmpans[bucket[tbuck] + bucketcnt[tbuck]] = ans[i] - H; + bucketcnt[tbuck]++; + } + } + /* 만약 정확히 길이가 K인 문자열 중 중복되는 것의 개수를 세려고 한다면, + * 여기서 처리하라. 그래야 bucketmark가 H인 상태로 남아 있고 + * (bucketmark가 같으면 그 자리에서 H글자만큼의 문자열은 같다는 뜻) + * 정렬은 2H 길이를 기준으로 되어 있으니까, tmpans를 이용하기. + * 부분 문자열의 길이 K는 H 이상 2 * H 이하여야 함. */ +// phase 2-2: identify new buckets + int lastbucket = bucketmark[tmpans[0]]; + for (i = 1 ; i < n ; i++) { + if (bucket[bucketmark[tmpans[i]]] != i) { + if (bucketupdate[tmpans[i]] != bucketupdate[tmpans[i - 1]]) { +// found new bucket + bucket[cntbucket] = i; + lastbucket = cntbucket; + cntbucket++; + } + } + else { + lastbucket = bucketmark[tmpans[i]]; + } + bucketmark[tmpans[i]] = lastbucket; + } +// phase 2-3: copy ans and calculate ians + int flg = 0; + bucketmark[n] = -1; + for (i = 0 ; i < n ; i++) { + if (bucketmark[tmpans[i]] == bucketmark[tmpans[i + 1]]) flg = 1; + ans[i] = tmpans[i]; + ians[ans[i]] = i; + bucketcnt[bucketmark[ans[i]]] = 0; + } + if (flg == 0) break; + } + return 0; +} \ No newline at end of file diff --git a/String Algorithms/suffix_with_lcp.cpp b/String Algorithms/suffix_with_lcp.cpp new file mode 100644 index 0000000..129dff1 --- /dev/null +++ b/String Algorithms/suffix_with_lcp.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +using namespace std; +// L: doubling method 정렬을 위한 정보 +// P[stp][i]: 길이가 1 << stp인 원래 문자열의 위치 i부터 시작하는 버켓 번호 +int N, i, stp, cnt; +int A[65536]; +struct entry { + int nr[2], p; +} L[65536]; +int P[17][65536]; +int suffix_array[65536]; +int lcp[65536]; // lcp(i, i + 1) +int cmp(struct entry a, struct entry b) { + return (a.nr[0] == b.nr[0]) ? (a.nr[1] < b.nr[1]) : (a.nr[0] < b.nr[0]); +} +Seoul National University 25 +// calclcp(x, y) = min(lcp[x], lcp[x + 1], ..., lcp[y - 1]) +// binary indexed tree needed for speedup +int calclcp(int x, int y) { // x, y: start position in original string + int k, ret = 0; + if (x == y) return N - x; + for (k = stp - 1 ; k >= 0 && x < N && y < N ; k--) + if (P[k][x] == P[k][y]) + x += 1 << k, y += 1 << k, ret += 1 << k; + return ret; +} +int main(void) { + int i; + scanf("%d", &N); + for (i = 0 ; i < N ; i++) { + scanf("%d", &A[i]); + P[0][i] = A[i]; + } + for (stp = 1, cnt = 1 ; (cnt >> 1) < N ; stp++, cnt <<= 1) { + for (i = 0 ; i < N ; i++) { + L[i].nr[0] = P[stp - 1][i]; + L[i].nr[1] = (i + cnt < N) ? P[stp - 1][i + cnt] : -1; + L[i].p = i; + } + sort(L, L + N, cmp); + for (i = 0 ; i < N ; i++) { + P[stp][L[i].p] = (i > 0 && L[i].nr[0] == L[i - 1].nr[0] + && L[i].nr[1] == L[i - 1].nr[1]) ? P[stp][L[i - 1].p] : i; + } + } + for (i = 0 ; i < N ; i++) + suffix_array[P[stp - 1][i]] = i; + for (i = 0 ; i + 1 < N ; i++) + lcp[i] = calclcp(i, i + 1); + return 0; +} \ No newline at end of file From 32716d7dd53cb9358807c2243d40b0b091165290 Mon Sep 17 00:00:00 2001 From: Manoj Pandey Date: Sun, 11 Oct 2015 16:18:28 +0530 Subject: [PATCH 8/9] formatted code --- .../ClosestPairOfPointsNurlan.cpp | 5 +- Computational Geometry/convex_hull.cpp | 9 +- .../general_geometry_library.cpp | 34 +++- Graph Algorithms/Dinic.cpp | 146 ------------------ Graph Algorithms/FordFulkerson.cpp | 104 ------------- 5 files changed, 41 insertions(+), 257 deletions(-) delete mode 100644 Graph Algorithms/Dinic.cpp delete mode 100644 Graph Algorithms/FordFulkerson.cpp diff --git a/Computational Geometry/ClosestPairOfPointsNurlan.cpp b/Computational Geometry/ClosestPairOfPointsNurlan.cpp index 72b1d35..16c8ee4 100644 --- a/Computational Geometry/ClosestPairOfPointsNurlan.cpp +++ b/Computational Geometry/ClosestPairOfPointsNurlan.cpp @@ -53,16 +53,20 @@ void closest_pair(point p[], int n) { closest_pair(p + m, n - m); //right int il = 0, ir = m, i = 0; + while (il < m && ir < n) { // merging two halves if (p[il].y < p[ir].y) aux[i ++] = p[il ++]; else aux[i ++] = p[ir ++]; } + while (il < m) aux[i ++] = p[il ++]; + while (ir < n) aux[i ++] = p[ir ++]; vn = 0; + for (int j = 0 ; j < n ; j ++) { // copying back into p p[j] = aux[j]; if (fabs(p[j].x - x) < ans) // looking at the strip of width 2*ans @@ -91,4 +95,3 @@ int main() { printf("%d %d %lf\n", min(a, b), max(a, b), ans); return 0; } - diff --git a/Computational Geometry/convex_hull.cpp b/Computational Geometry/convex_hull.cpp index 6d775fe..e734f0a 100644 --- a/Computational Geometry/convex_hull.cpp +++ b/Computational Geometry/convex_hull.cpp @@ -1,27 +1,33 @@ #include #include #include + using namespace std; const double eps = 1e-9; + inline int diff(double lhs, double rhs) { if (lhs - eps < rhs && rhs < lhs + eps) return 0; return (lhs < rhs) ? -1 : 1; } + struct Point { double x, y; Point() {} Point(double x_, double y_): x(x_), y(y_) {} }; + inline int ccw(const Point& a, const Point& b, const Point& c) { return diff(a.x * b.y + b.x * c.y + c.x * a.y - a.y * b.x - b.y * c.x - c.y * a.x, 0); } + inline double dist2(const Point &a, const Point &b) { double dx = a.x - b.x; double dy = a.y - b.y; return dx * dx + dy * dy; } + struct PointSorter { Point origin; PointSorter(const vector& points) { @@ -42,6 +48,7 @@ struct PointSorter { return det < 0; } }; + vector convex_hull(vector points) { if (points.size() <= 3) return points; @@ -57,4 +64,4 @@ vector convex_hull(vector points) { ans.push_back(points[i]); } return ans; -} \ No newline at end of file +} diff --git a/Computational Geometry/general_geometry_library.cpp b/Computational Geometry/general_geometry_library.cpp index 55250a2..426d987 100644 --- a/Computational Geometry/general_geometry_library.cpp +++ b/Computational Geometry/general_geometry_library.cpp @@ -1,64 +1,82 @@ #include #include + using namespace std; + const double eps = 1e-9; + inline int diff(double lhs, double rhs) { if (lhs - eps < rhs && rhs < lhs + eps) return 0; return (lhs < rhs) ? -1 : 1; } + inline bool is_between(double check, double a, double b) { if (a < b) return (a - eps < check && check < b + eps); else return (b - eps < check && check < a + eps); } + struct Point { double x, y; + Point() {} Point(double x_, double y_): x(x_), y(y_) {} + bool operator==(const Point& rhs) const { return diff(x, rhs.x) == 0 && diff(y, rhs.y) == 0; } + const Point operator+(const Point& rhs) const { return Point(x + rhs.x, y + rhs.y); } + const Point operator-(const Point& rhs) const { return Point(x - rhs.x, y - rhs.y); } + const Point operator*(double t) const { return Point(x * t, y * t); } }; -Seoul National University 19 + struct Circle { Point center; double r; Circle() {} Circle(const Point& center_, double r_): center(center_), r(r_) {} }; + struct Line { Point pos, dir; Line() {} Line(const Point& pos_, const Point& dir_): pos(pos_), dir(dir_) {} }; + inline double inner(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y; } + inline double outer(const Point& a, const Point& b) { return a.x * b.y - a.y * b.x; } + inline int ccw_line(const Line& line, const Point& point) { return diff(outer(line.dir, point - line.pos), 0); } + inline int ccw(const Point& a, const Point& b, const Point& c) { return diff(outer(b - a, c - a), 0); } + inline double dist(const Point& a, const Point& b) { return sqrt(inner(a - b, a - b)); } + inline double dist2(const Point &a, const Point &b) { return inner(a - b, a - b); } + inline double dist(const Line& line, const Point& point, bool segment = false) { double c1 = inner(point - line.pos, line.dir); if (segment && diff(c1, 0) <= 0) return dist(line.pos, point); @@ -66,6 +84,7 @@ inline double dist(const Line& line, const Point& point, bool segment = false) { if (segment && diff(c2, c1) <= 0) return dist(line.pos + line.dir, point); return dist(line.pos + line.dir * (c1 / c2), point); } + bool get_cross(const Line& a, const Line& b, Point& ret) { double mdet = outer(b.dir, a.dir); if (diff(mdet, 0) == 0) return false; @@ -73,6 +92,7 @@ bool get_cross(const Line& a, const Line& b, Point& ret) { ret = b.pos + b.dir * t2; return true; } + bool get_segment_cross(const Line& a, const Line& b, Point& ret) { double mdet = outer(b.dir, a.dir); if (diff(mdet, 0) == 0) return false; @@ -82,6 +102,7 @@ bool get_segment_cross(const Line& a, const Line& b, Point& ret) { ret = b.pos + b.dir * t2; return true; } + const Point inner_center(const Point &a, const Point &b, const Point &c) { double wa = dist(b, c), wb = dist(c, a), wc = dist(a, b); double w = wa + wb + wc; @@ -89,6 +110,7 @@ const Point inner_center(const Point &a, const Point &b, const Point &c) { (wa * a.x + wb * b.x + wc * c.x) / w, (wa * a.y + wb * b.y + wc * c.y) / w); } + const Point outer_center(const Point &a, const Point &b, const Point &c) { Point d1 = b - a, d2 = c - a; double area = outer(d1, d2); @@ -98,6 +120,7 @@ const Point outer_center(const Point &a, const Point &b, const Point &c) { + d1.x * d2.x * (d1.x - d2.y); return Point(a.x + dx / area / 2.0, a.y - dy / area / 2.0); } + vector circle_line(const Circle& circle, const Line& line) { vector result; double a = 2 * inner(line.dir, line.dir); @@ -117,6 +140,7 @@ vector circle_line(const Circle& circle, const Line& line) { } return result; } + vector circle_circle(const Circle& a, const Circle& b) { vector result; int pred = diff(dist(a.center, b.center), a.r + b.r); @@ -137,6 +161,7 @@ vector circle_circle(const Circle& a, const Circle& b) { return circle_line(a, Line(Point(tmp / cdiff.x, 0), Point(-cdiff.y, cdiff.x))); } + const Circle circle_from_3pts(const Point& a, const Point& b, const Point& c) { Point ba = b - a, cb = c - b; Line p((a + b) * 0.5, Point(ba.y, -ba.x)); @@ -148,6 +173,7 @@ const Circle circle_from_3pts(const Point& a, const Point& b, const Point& c) { circle.r = dist(circle.center, a); return circle; } + const Circle circle_from_2pts_rad(const Point& a, const Point& b, double r) { double det = r * r / dist2(a, b) - 0.25; Circle circle; @@ -155,11 +181,9 @@ const Circle circle_from_2pts_rad(const Point& a, const Point& b, double r) { circle.r = -1; else { double h = sqrt(det); -// center is to the left of a->b + // center is to the left of a->b circle.center = (a + b) * 0.5 + Point(a.y - b.y, b.x - a.x) * h; circle.r = r; } return circle; -} - - +} \ No newline at end of file diff --git a/Graph Algorithms/Dinic.cpp b/Graph Algorithms/Dinic.cpp deleted file mode 100644 index 14c0003..0000000 --- a/Graph Algorithms/Dinic.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/******************************************************************************** - - MaxFlow Dinic algorithm with scaling. - O(N * M * log(MC)), where MC is maximum edge capacity. - - Based on problem 2784 from informatics.mccme.ru - http://informatics.mccme.ru/mod/statements/view3.php?chapterid=2784#1 - -********************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -struct edge { - int a, b, f, c; -}; - -const int inf = 1000 * 1000 * 1000; -const int MAXN = 1050; - -int n, m; -vector e; -int pt[MAXN]; // very important performance trick -vector g[MAXN]; -long long flow = 0; -queue q; -int d[MAXN]; -int lim; -int s, t; - -void add_edge(int a, int b, int c) { - edge ed; - - //keep edges in vector: e[ind] - direct edge, e[ind ^ 1] - back edge - - ed.a = a; ed.b = b; ed.f = 0; ed.c = c; - g[a].push_back(e.size()); - e.push_back(ed); - - ed.a = b; ed.b = a; ed.f = c; ed.c = c; - g[b].push_back(e.size()); - e.push_back(ed); -} - -bool bfs() { - for (int i = s; i <= t; i++) - d[i] = inf; - d[s] = 0; - q.push(s); - while (!q.empty() && d[t] == inf) { - int cur = q.front(); q.pop(); - for (size_t i = 0; i < g[cur].size(); i++) { - int id = g[cur][i]; - int to = e[id].b; - - //printf("cur = %d id = %d a = %d b = %d f = %d c = %d\n", cur, id, e[id].a, e[id].b, e[id].f, e[id].c); - - if (d[to] == inf && e[id].c - e[id].f >= lim) { - d[to] = d[cur] + 1; - q.push(to); - } - } - } - while (!q.empty()) - q.pop(); - return d[t] != inf; -} - -bool dfs(int v, int flow) { - if (flow == 0) - return false; - if (v == t) { - //cout << v << endl; - return true; - } - for (; pt[v] < g[v].size(); pt[v]++) { - int id = g[v][pt[v]]; - int to = e[id].b; - - //printf("v = %d id = %d a = %d b = %d f = %d c = %d\n", v, id, e[id].a, e[id].b, e[id].f, e[id].c); - - if (d[to] == d[v] + 1 && e[id].c - e[id].f >= flow) { - int pushed = dfs(to, flow); - if (pushed) { - e[id].f += flow; - e[id ^ 1].f -= flow; - return true; - } - } - } - return false; -} - -void dinic() { - for (lim = (1 << 30); lim >= 1;) { - if (!bfs()) { - lim >>= 1; - continue; - } - - for (int i = s; i <= t; i++) - pt[i] = 0; - - int pushed; - - while (pushed = dfs(s, lim)) { - flow = flow + lim; - } - - //cout << flow << endl; - } -} - -int main() { - //freopen("input.txt","r",stdin); - //freopen("output.txt","w",stdout); - scanf("%d %d", &n, &m); - - s = 1; t = n; - - for (int i = 1; i <= m; i++) { - int a, b, c; - scanf("%d %d %d", &a, &b, &c); - add_edge(a, b, c); - } - - dinic(); - - cout << flow << endl; - - return 0; -} diff --git a/Graph Algorithms/FordFulkerson.cpp b/Graph Algorithms/FordFulkerson.cpp deleted file mode 100644 index 99cf517..0000000 --- a/Graph Algorithms/FordFulkerson.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************** - - MaxFlow Ford-Fulkerson algorithm. O(M|f|), |f| - maxflow value - Based on problem 2783 from informatics.mccme.ru - http://informatics.mccme.ru/mod/statements/view3.php?chapterid=2783#1 - -********************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -const int MAXN = 1050; -const int INF = (int) 1e9; - -struct edge { - int from, to, f, cap; -}; - -int n, m; -vector e; -vector g[MAXN]; -bool used[MAXN]; -int s, t; -int ans; - -void addEdge(int from, int to, int cap) { - edge ed; - - ed.from = from; ed.to = to; ed.f = 0; ed.cap = cap; - e.push_back(ed); - g[from].push_back((int) e.size() - 1); - - ed.from = to; ed.to = from; ed.f = cap; ed.cap = cap; - e.push_back(ed); - g[to].push_back((int) e.size() - 1); -} - -int pushFlow(int v, int flow = INF) { - used[v] = true; - if (v == t) - return flow; - - for (int i = 0; i < (int) g[v].size(); i++) { - int ind = g[v][i]; - int to = e[ind].to; - int f = e[ind].f; - int cap = e[ind].cap; - - if (used[to] || cap - f == 0) - continue; - - int pushed = pushFlow(to, min(flow, cap - f)); - if (pushed > 0) { - e[ind].f += pushed; - e[ind ^ 1].f -= pushed; - return pushed; - } - } - - return 0; -} - -int main() { - //assert(freopen("input.txt","r",stdin)); - //assert(freopen("output.txt","w",stdout)); - - scanf("%d %d", &n, &m); - - s = 1; t = n; - - for (int i = 1; i <= m; i++) { - int from, to, cap; - scanf("%d %d %d", &from, &to, &cap); - addEdge(from, to, cap); - } - - while (true) { - memset(used, 0, sizeof(used)); - int add = pushFlow(s); - if (add == 0) - break; - ans += add; - } - - printf("%d\n", ans); - - return 0; -} \ No newline at end of file From c5b312fb6f0af7539a09eaee472e0467e5dc396c Mon Sep 17 00:00:00 2001 From: adityag3 Date: Mon, 31 Oct 2016 16:28:07 +0530 Subject: [PATCH 9/9] Emoji removed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7da8ff..3407476 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,4 @@ Right now, all the topics are being added from this [Google Doc file](https://do How to Contribute ==================== -Open a new issue to start a new discussion. It will be helpful if new ideas are also presented to handle this repository. Thanks :) +Open a new issue to start a new discussion. It will be helpful if new ideas are also presented to handle this repository. Thanks