diff --git a/graph/connected_components_of_complement_graph/checker.cpp b/graph/connected_components_of_complement_graph/checker.cpp new file mode 100644 index 000000000..7c6ece45a --- /dev/null +++ b/graph/connected_components_of_complement_graph/checker.cpp @@ -0,0 +1,41 @@ +#include "testlib.h" +#include +#include + +using namespace std; + +vector> read_ans(int n, InStream &stream) { + int k = stream.readInt(1, n); + vector> cc(k); + vector pos(n, -1); + for (int i = 0; i < k; i++) { + int l = stream.readInt(1, n); + cc[i] = vector(l); + for (int j = 0; j < l; j++) { + cc[i][j] = stream.readInt(0, n - 1); + if (pos[cc[i][j]] != -1) { + stream.quitf(_wa, "twice used vertex %d", cc[i][j]); + } + pos[cc[i][j]] = i; + } + sort(cc[i].begin(), cc[i].end()); + } + sort(cc.begin(), cc.end()); + return cc; +} + +int main(int argc, char *argv[]) { + registerTestlibCmd(argc, argv); + int n = inf.readInt(); + auto cc_ans = read_ans(n, ans); + auto cc_ouf = read_ans(n, ouf); + int k_ans = int(cc_ans.size()); + int k_ouf = int(cc_ouf.size()); + if (k_ans != k_ouf) { + quitf(_wa, "# of connected components is wrong - expected: '%d', found: '%d'", k_ans, k_ouf); + } + if (cc_ans != cc_ouf) { + quitf(_wa, "connected components are different"); + } + quitf(_ok, "OK"); +} diff --git a/graph/connected_components_of_complement_graph/gen/complement_of_many_paths.cpp b/graph/connected_components_of_complement_graph/gen/complement_of_many_paths.cpp new file mode 100644 index 000000000..463ac135c --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/complement_of_many_paths.cpp @@ -0,0 +1,53 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int get_max_n() { + int ok = N_MIN, ng = N_MAX + 1; + while (ng - ok > 1) { + int mid = (ok + ng) / 2; + if ((long long)mid * (mid - 1) / 2 <= M_MAX) { + ok = mid; + } else { + ng = mid; + } + } + return ok; +} + +int main(int, char **argv) { + long long seed = atoll(argv[1]); + Random gen(seed); + int n = get_max_n(); + vector p(n); + for (int i = 0; i < n; ++i) { + p[i] = i; + } + gen.shuffle(p.begin(), p.end()); + vector> edge(n, vector(n, 1)); + for (int i = 0; i < n - 1; ++i) { + if (gen.uniform_bool()) { + edge[p[i]][p[i + 1]] = edge[p[i + 1]][p[i]] = 0; + } + } + vector> output; + for (int i = 0; i < n; ++i) { + for (int j = i + 1; j < n; ++j) { + if (edge[i][j]) { + if (gen.uniform_bool()) { + output.emplace_back(i, j); + } else { + output.emplace_back(j, i); + } + } + } + } + gen.shuffle(output.begin(), output.end()); + int m = int(output.size()); + printf("%d %d\n", n, m); + for (pair e : output) { + printf("%d %d\n", e.first, e.second); + } +} diff --git a/graph/connected_components_of_complement_graph/gen/complement_of_sparse.cpp b/graph/connected_components_of_complement_graph/gen/complement_of_sparse.cpp new file mode 100644 index 000000000..2f8342118 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/complement_of_sparse.cpp @@ -0,0 +1,51 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int get_max_n() { + int ok = N_MIN, ng = N_MAX + 1; + while (ng - ok > 1) { + int mid = (ok + ng) / 2; + if ((long long)mid * (mid - 1) / 2 <= M_MAX) { + ok = mid; + } else { + ng = mid; + } + } + return ok; +} + +int main(int, char **argv) { + long long seed = atoll(argv[1]); + Random gen(seed); + int n = get_max_n(); + int elim = n / 2; + vector> edge(n, vector(n, 1)); + for (int i = 0; i < elim; ++i) { + pair p = gen.uniform_pair(0, n - 1); + while (!edge[p.first][p.second]) { + p = gen.uniform_pair(0, n - 1); + } + edge[p.first][p.second] = 0; + } + vector> output; + for (int i = 0; i < n; ++i) { + for (int j = i + 1; j < n; ++j) { + if (edge[i][j]) { + if (gen.uniform_bool()) { + output.emplace_back(i, j); + } else { + output.emplace_back(j, i); + } + } + } + } + gen.shuffle(output.begin(), output.end()); + int m = int(output.size()); + printf("%d %d\n", n, m); + for (pair e : output) { + printf("%d %d\n", e.first, e.second); + } +} diff --git a/graph/connected_components_of_complement_graph/gen/complete.cpp b/graph/connected_components_of_complement_graph/gen/complete.cpp new file mode 100644 index 000000000..eb75983b9 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/complete.cpp @@ -0,0 +1,40 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int get_max_n() { + int ok = N_MIN, ng = N_MAX + 1; + while (ng - ok > 1) { + int mid = (ok + ng) / 2; + if ((long long)mid * (mid - 1) / 2 <= M_MAX) { + ok = mid; + } else { + ng = mid; + } + } + return ok; +} + +int main(int, char **argv) { + long long seed = atoll(argv[1]); + Random gen(seed); + int n = get_max_n(); + int m = n * (n - 1) / 2; + vector> edges; + for (int i = 0; i < n; ++i) { + for (int j = i + 1; j < n; ++j) { + if (gen.uniform_bool()) { + edges.emplace_back(i, j); + } else { + edges.emplace_back(j, i); + } + } + } + gen.shuffle(edges.begin(), edges.end()); + printf("%d %d\n", n, m); + for (pair e : edges) { + printf("%d %d\n", e.first, e.second); + } +} diff --git a/graph/connected_components_of_complement_graph/gen/example_00.in b/graph/connected_components_of_complement_graph/gen/example_00.in new file mode 100644 index 000000000..00ed2c51c --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/example_00.in @@ -0,0 +1,4 @@ +4 3 +1 0 +2 1 +1 3 diff --git a/graph/connected_components_of_complement_graph/gen/example_01.in b/graph/connected_components_of_complement_graph/gen/example_01.in new file mode 100644 index 000000000..a802cdf46 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/example_01.in @@ -0,0 +1,12 @@ +6 11 +0 1 +0 2 +0 4 +1 2 +1 3 +1 5 +2 3 +2 4 +2 5 +3 4 +4 5 diff --git a/graph/connected_components_of_complement_graph/gen/example_02.in b/graph/connected_components_of_complement_graph/gen/example_02.in new file mode 100644 index 000000000..3f1dcc525 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/example_02.in @@ -0,0 +1,11 @@ +5 10 +0 1 +0 2 +0 3 +0 4 +1 2 +1 3 +1 4 +2 3 +2 4 +3 4 diff --git a/graph/connected_components_of_complement_graph/gen/max_random.cpp b/graph/connected_components_of_complement_graph/gen/max_random.cpp new file mode 100644 index 000000000..d260ee624 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/max_random.cpp @@ -0,0 +1,26 @@ +#include "../params.h" +#include "random.h" +#include + +using namespace std; + +int main(int, char **argv) { + long long seed = atoll(argv[1]); + Random gen(seed); + int n = N_MAX; + int m = M_MAX; + printf("%d %d\n", n, m); + set> edges; + for (int i = 0; i < m; i++) { + pair p = gen.uniform_pair(0, n - 1); + while (edges.count(p)) { + p = gen.uniform_pair(0, n - 1); + } + edges.insert(p); + if (gen.uniform_bool()) { + swap(p.first, p.second); + } + printf("%d %d\n", p.first, p.second); + } + return 0; +} diff --git a/graph/connected_components_of_complement_graph/gen/minimum_00.in b/graph/connected_components_of_complement_graph/gen/minimum_00.in new file mode 100644 index 000000000..80c0cc79a --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/minimum_00.in @@ -0,0 +1 @@ +1 0 diff --git a/graph/connected_components_of_complement_graph/gen/minimum_01.in b/graph/connected_components_of_complement_graph/gen/minimum_01.in new file mode 100644 index 000000000..a74b3c230 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/minimum_01.in @@ -0,0 +1 @@ +2 0 diff --git a/graph/connected_components_of_complement_graph/gen/minimum_02.in b/graph/connected_components_of_complement_graph/gen/minimum_02.in new file mode 100644 index 000000000..5d0dfc619 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/minimum_02.in @@ -0,0 +1,2 @@ +2 1 +0 1 diff --git a/graph/connected_components_of_complement_graph/gen/no_edge.cpp b/graph/connected_components_of_complement_graph/gen/no_edge.cpp new file mode 100644 index 000000000..3015f1497 --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/no_edge.cpp @@ -0,0 +1,10 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main() { + int n = N_MAX; + printf("%d 0\n", n); +} diff --git a/graph/connected_components_of_complement_graph/gen/star.cpp b/graph/connected_components_of_complement_graph/gen/star.cpp new file mode 100644 index 000000000..11a68d7ba --- /dev/null +++ b/graph/connected_components_of_complement_graph/gen/star.cpp @@ -0,0 +1,20 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main(int, char **argv) { + long long seed = atoll(argv[1]); + Random gen(seed); + int n = N_MAX; + int m = n - 1; + printf("%d %d\n", n, m); + int center = gen.uniform(0, n - 1); + for (int i = 0; i < n; ++i) { + if (i != center) { + printf("%d %d\n", i, center); + } + } + return 0; +} diff --git a/graph/connected_components_of_complement_graph/hash.json b/graph/connected_components_of_complement_graph/hash.json new file mode 100644 index 000000000..41592afbe --- /dev/null +++ b/graph/connected_components_of_complement_graph/hash.json @@ -0,0 +1,50 @@ +{ + "complement_of_many_paths_00.in": "d65e1ab32040a0bea5fba707c4efb2a5a7e807782321deeb406a7f4f1b465f5b", + "complement_of_many_paths_00.out": "cdc1527d07a6ca3e01911435701ce96a69eacc3832165226322803cff94ceed4", + "complement_of_many_paths_01.in": "730169db156d0b22aa636192704e3b7c9656dae9910c6b71e8014f40999e32bf", + "complement_of_many_paths_01.out": "4b0d54b0aeb7019a1882abede61e993488b5e5ff4b91ba8844cd3d47d030d816", + "complement_of_many_paths_02.in": "2f61b917fa62b0fed283a83f12c126eab7757e036123427d94e03ddd30319163", + "complement_of_many_paths_02.out": "2a8531faf64b9866619c73d3c62c3f112378d97835c022951037fde1e4a5b1f4", + "complement_of_many_paths_03.in": "bf7c86a8075a9801a4af07a117ec6641db8cc303ae7c058c4df3cf85b1ba4061", + "complement_of_many_paths_03.out": "d8191837dd846fc196194db27021092e827f6adf3ec8721aede3bbfd70d66350", + "complement_of_many_paths_04.in": "8944b42f26c76509535b042ef086baf5b3e60585464dabae3d4802d2c41f0a96", + "complement_of_many_paths_04.out": "13124f1bf67902e5fbf94473814d0c78c531062793b56b6ee3dd6959a1d00592", + "complement_of_sparse_00.in": "251902d016057f034341c640e113a3e82711cf09559536730afb283a75cf63d5", + "complement_of_sparse_00.out": "6d33f036779397b12e02b45c8f9704cf0351f7565c02fd7011cc248489f4b351", + "complement_of_sparse_01.in": "b9fa1104af50f819007fc3a80cd927a5e4e4cb03418adfd75f8d7260e5888ccd", + "complement_of_sparse_01.out": "87a94c39bb9731c01a7b5221b1b58b9724987813b49ccdf068291f4f3cd7dc4d", + "complement_of_sparse_02.in": "02ce9a1e3114889e31c0818ff2ab16b5c76d9603b418bbf91b9c2c2cfc375fd5", + "complement_of_sparse_02.out": "3430ad4bc27be56f226660ff22a4cfce17e206e3889895f0c42698e32413be13", + "complement_of_sparse_03.in": "0e55335fd3f424abed344fab7121d053823c7bb4571deb77cc99bda4831c14b8", + "complement_of_sparse_03.out": "85b2a9d3a187e72a47868e7259e3fd7bd2118c96dc99d247686eca741f286134", + "complement_of_sparse_04.in": "37a570d2fdb458bafbaaf45f747b35e9b9b69de237c566c1edfb9323576d8223", + "complement_of_sparse_04.out": "7937a006eccc0777079ed7f97aebd532c32b73b16325d5be41c6d264cdfeef09", + "complete_00.in": "8bb85cdf8012121788be0cb8de070cbc32dcb0b14313e436186d03a547465544", + "complete_00.out": "35356cffdcbcc676fd205a1a60951fd428282b3f0dbbda2c2229e81e15c0da01", + "example_00.in": "8cf683df6c2f5c13cd326ac07f51e798e5e194003f4f6e088d895148e2a9b763", + "example_00.out": "672ea5ac34d7c51cd5d4a75041ebe858028be1e2002f0b2ae6b21909ecdf83fe", + "example_01.in": "e0a2c1655d6f02bb4477782e4e836a12abeb82736aafff072fab6561276110be", + "example_01.out": "322c5b3204d4655974829c59f083abf32c7b52f3bd559597e145210f9cab0d66", + "example_02.in": "02f369096b911556d342f347851a6f997d3766501c956bed1b4e3ed810a8fc42", + "example_02.out": "19826a18b764e5541b7cf62880f68fdbf1b954169b3e838d72cf1071ea558170", + "max_random_00.in": "583ed8977219941c3bbed07acb8ca21e83de4b0aef7989866da5bf6a080285ac", + "max_random_00.out": "219da5b597741168f705e7eeec1102c50593f23ec03d47fbd8d38d5f54c8b811", + "max_random_01.in": "af9b4489be6193c78900526eea0e11af5b708e484fec3922bab6afb58e9bafc5", + "max_random_01.out": "219da5b597741168f705e7eeec1102c50593f23ec03d47fbd8d38d5f54c8b811", + "max_random_02.in": "5e2fa069562b07caf7fba6d007c9e15008385d9d1375ac19232f0d4bad3d7a92", + "max_random_02.out": "219da5b597741168f705e7eeec1102c50593f23ec03d47fbd8d38d5f54c8b811", + "max_random_03.in": "336c7920dd6138ef0ca565a8579e5d631e6785c2f87aa84ea6bfc79030eac2af", + "max_random_03.out": "219da5b597741168f705e7eeec1102c50593f23ec03d47fbd8d38d5f54c8b811", + "max_random_04.in": "6b3fc157c048daf0e1b3fedaa4ca3ebd160da73b8a6fae1c82d1bfa244da52e7", + "max_random_04.out": "219da5b597741168f705e7eeec1102c50593f23ec03d47fbd8d38d5f54c8b811", + "minimum_00.in": "f4a8ae8e74ddfb896a256de4e3099911dcaa6a9302591713898069b0bcd6e3d7", + "minimum_00.out": "d17b405c22d3ea8fea3ac06a001c501c1d7e5a328083f5d4a5bcce4fd97e30da", + "minimum_01.in": "4516f6eaaa675488778d6ca333df14bc68c27fb7d7b8015073220d4571aa9c51", + "minimum_01.out": "67d4a29a53c61fb2de135f2059cedf70735135da8d2a6848dc0bf5d574d5eab8", + "minimum_02.in": "4a6ae7226283a4b6277ce3e77a91585c0cad93929046f3c7bd9105d7ed101834", + "minimum_02.out": "ed9340df2899edec904960adcd2539fe18f6e765051e6bbbd5aaccc02b6f8d05", + "no_edge_00.in": "5fc37b8e820c7ecfdaf122cdc5a0e1e9174d5d09d0b9c7aae8aeac434ca26aed", + "no_edge_00.out": "219da5b597741168f705e7eeec1102c50593f23ec03d47fbd8d38d5f54c8b811", + "star_00.in": "81ee21ae7add6b764b36888d0c9703ab616e634c17260735cf1087f5dd14a962", + "star_00.out": "d77af3500c0728e06c0b134a8f2c92ad1c3cc62b97f2f2c44d3b4f1016e6a76a" +} \ No newline at end of file diff --git a/graph/connected_components_of_complement_graph/info.toml b/graph/connected_components_of_complement_graph/info.toml new file mode 100644 index 000000000..edba6c37c --- /dev/null +++ b/graph/connected_components_of_complement_graph/info.toml @@ -0,0 +1,38 @@ +title = 'Connected Components of Complement Graph' +timelimit = 5.0 +forum = "https://github.com/yosupo06/library-checker-problems/issues/865" + +[[tests]] + name = "example.in" + number = 3 +[[tests]] + name = "max_random.cpp" + number = 5 +[[tests]] + name = "no_edge.cpp" + number = 1 +[[tests]] + name = "complete.cpp" + number = 1 +[[tests]] + name = "star.cpp" + number = 1 +[[tests]] + name = "complement_of_sparse.cpp" + number = 5 +[[tests]] + name = "complement_of_many_paths.cpp" + number = 5 +[[tests]] + name = "minimum.in" + number = 3 + +[[solutions]] + name = "naive.cpp" + allow_tle = true + +[params] + N_MIN = 1 + N_MAX = 500_000 + M_MIN = 0 + M_MAX = 500_000 diff --git a/graph/connected_components_of_complement_graph/sol/correct.cpp b/graph/connected_components_of_complement_graph/sol/correct.cpp new file mode 100644 index 000000000..007d8a389 --- /dev/null +++ b/graph/connected_components_of_complement_graph/sol/correct.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +using namespace std; + +int main() { + int n, m; + scanf("%d%d", &n, &m); + vector> g(n); + for (int i = 0; i < m; ++i) { + int a, b; + scanf("%d%d", &a, &b); + g[a].push_back(b); + g[b].push_back(a); + } + vector cc(n, -1); + int cnt = 0; + vector rem(n); + for (int i = 0; i < n; ++i) { + rem[i] = i; + } + vector flg(n, 0); + while (!rem.empty()) { + int r = rem.back(); + rem.pop_back(); + queue que; + cc[r] = cnt; + que.push(r); + while (!que.empty()) { + int v = que.front(); + que.pop(); + for (int u : g[v]) { + flg[u] = 1; + } + vector nxtrem; + for (int u : rem) { + if (flg[u]) { + nxtrem.push_back(u); + } else if (cc[u] == -1) { + cc[u] = cnt; + que.push(u); + } + } + for (int u : g[v]) { + flg[u] = 0; + } + rem = nxtrem; + } + ++cnt; + } + vector> comps(cnt); + for (int i = 0; i < n; ++i) { + comps[cc[i]].push_back(i); + } + printf("%d\n", cnt); + for (int i = 0; i < cnt; ++i) { + printf("%d", (int)comps[i].size()); + for (int u : comps[i]) { + printf(" %d", u); + } + printf("\n"); + } +} diff --git a/graph/connected_components_of_complement_graph/sol/naive.cpp b/graph/connected_components_of_complement_graph/sol/naive.cpp new file mode 100644 index 000000000..991006152 --- /dev/null +++ b/graph/connected_components_of_complement_graph/sol/naive.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +using namespace std; + +int main() { + int n, m; + scanf("%d%d", &n, &m); + set> edges; + for (int i = 0; i < m; ++i) { + int a, b; + scanf("%d%d", &a, &b); + edges.insert(make_pair(a, b)); + edges.insert(make_pair(b, a)); + } + vector cc(n, -1); + int cnt = 0; + for (int i = 0; i < n; ++i) { + if (cc[i] != -1) { + continue; + } + queue que; + cc[i] = cnt; + que.push(i); + while (!que.empty()) { + int v = que.front(); + que.pop(); + for (int u = 0; u < n; ++u) { + if (!edges.count(make_pair(u, v)) && cc[u] == -1) { + cc[u] = cnt; + que.push(u); + } + } + } + ++cnt; + } + vector> comps(cnt); + for (int i = 0; i < n; ++i) { + comps[cc[i]].push_back(i); + } + printf("%d\n", cnt); + for (int i = 0; i < cnt; ++i) { + printf("%d", (int)comps[i].size()); + for (int u : comps[i]) { + printf(" %d", u); + } + printf("\n"); + } +} diff --git a/graph/connected_components_of_complement_graph/task.md b/graph/connected_components_of_complement_graph/task.md new file mode 100644 index 000000000..7455063e9 --- /dev/null +++ b/graph/connected_components_of_complement_graph/task.md @@ -0,0 +1,69 @@ +## @{keyword.statement} + +@{lang.en} + +You are given a simple undirected graph with $N$ vertices and $M$ edges. The $i$-th edge is $(a_i,b_i)$. Decompose the complement graph of $G$ into connected components. + +@{lang.ja} + +$N$ 頂点 $M$ 辺の単純無向グラフ $G$ が与えられる。$i$ 番目の辺は $(a_i,b_i)$ である。$G$ の補グラフを連結成分分解せよ。 + +@{lang.end} + +## @{keyword.constraints} + +@{lang.en} + +- $@{param.N_MIN} \leq N \leq @{param.N_MAX}$ +- $@{param.M_MIN} \leq M \leq @{param.M_MAX}$ +- $0 \leq a_i, b_i < N$ +- The given graph is simple + +@{lang.ja} + +- $@{param.N_MIN} \leq N \leq @{param.N_MAX}$ +- $@{param.M_MIN} \leq M \leq @{param.M_MAX}$ +- $0 \leq a_i, b_i < N$ +- 与えられるグラフは単純 + +@{lang.end} + +## @{keyword.input} + +~~~ +$N$ $M$ +$a_0$ $b_0$ +$a_1$ $b_1$ +$\vdots$ +$a_{M-1}$ $b_{M-1}$ +~~~ + +## @{keyword.output} + +@{lang.en} + +Print the number of connected components $K$ in the first line. In the next $K$ lines, print as follows. $l$ is the number of vertices of a connected component and $v_i$ is a vertex index. + +@{lang.ja} + +$K$ を連結成分の個数として、$1+K$ 行出力する。最初の行には $K$ を出力し、その後 $K$ 行では以下のように出力する。$l$ は連結成分の頂点数であり、$v_i$ はその頂点番号である。 + +@{lang.end} + +~~~ +$l$ $v_0$ $v_1$ ... $v_{l-1}$ +~~~ + +@{lang.en} +If there are multiple solutions, you may print any of them. +@{lang.ja} +正しい出力が複数存在する場合は、どれを出力しても構わない。 +@{lang.end} + +## @{keyword.sample} + +@{example.example_00} + +@{example.example_01} + +@{example.example_02} diff --git a/graph/connected_components_of_complement_graph/verifier.cpp b/graph/connected_components_of_complement_graph/verifier.cpp new file mode 100644 index 000000000..98832e50a --- /dev/null +++ b/graph/connected_components_of_complement_graph/verifier.cpp @@ -0,0 +1,27 @@ +#include "testlib.h" +#include "params.h" +#include +#include +using namespace std; + +int main() { + registerValidation(); + int n = inf.readInt(N_MIN, N_MAX); + inf.readSpace(); + int m = inf.readInt(M_MIN, M_MAX); + inf.readChar('\n'); + set> edges; + for (int i = 0; i < m; ++i) { + int a = inf.readInt(0, n - 1); + inf.readSpace(); + int b = inf.readInt(0, n - 1); + inf.readChar('\n'); + ensure(a != b); + if (a > b) { + swap(a, b); + } + ensure(edges.count(make_pair(a, b)) == 0); + edges.insert(make_pair(a, b)); + } + inf.readEof(); +}