結果
問題 | No.3034 コーエン-マコーレー抽象単体複体 |
ユーザー |
![]() |
提出日時 | 2025-01-21 20:31:25 |
言語 | D (dmd 2.109.1) |
結果 |
WA
|
実行時間 | - |
コード長 | 5,356 bytes |
コンパイル時間 | 3,083 ms |
コンパイル使用メモリ | 101,624 KB |
実行使用メモリ | 7,792 KB |
最終ジャッジ日時 | 2025-02-06 22:24:10 |
合計ジャッジ時間 | 3,586 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | WA * 4 |
other | WA * 36 |
ソースコード
import std.algorithm, std.array, std.conv, std.stdio, std.typecons;alias Edge = Tuple!(uint, uint);alias EdgeSet = bool[Edge];alias Face = Tuple!(uint, uint, uint);alias FaceSet = bool[Face];alias ASC = Tuple!(EdgeSet, "edges", FaceSet, "faces");ASC create_normalized_asc(uint[][] face_list, ref uint N) {// normalizebool[uint] verts;foreach (face; face_list) {verts[face[0]] = true;verts[face[1]] = true;verts[face[2]] = true;}uint[uint] nv;uint N2;foreach (i; 1 .. N+1) {if (i in verts) nv[i] = N2++;}N = N2;EdgeSet edges;FaceSet faces;foreach (face; face_list) {edges[Edge(nv[face[0]], nv[face[1]])] = true;edges[Edge(nv[face[0]], nv[face[2]])] = true;edges[Edge(nv[face[1]], nv[face[2]])] = true;faces[Face(nv[face[0]], nv[face[1]], nv[face[2]])] = true;}return ASC(edges, faces);}// check if the ASC asc is connectedbool is_connected(ASC asc, uint N) {bool[uint] vertex_set;auto uf = new UnionFind(N);foreach (face; asc.faces.keys) {uf.unite(face[0], face[1]);uf.unite(face[0], face[2]);vertex_set[face[0]] = vertex_set[face[1]] = vertex_set[face[2]] = true;}foreach (edge; asc.edges.keys) {uf.unite(edge[0], edge[1]);vertex_set[edge[0]] = vertex_set[edge[1]] = true;}return uf.size(vertex_set.keys[0]) == vertex_set.length;}// calculate link {i} for each iASC[] links(ASC asc, uint N) {auto result = new ASC[N];foreach (face; asc.faces.keys) {result[face[0]].edges[Edge(face[1], face[2])] = true;result[face[1]].edges[Edge(face[0], face[2])] = true;result[face[2]].edges[Edge(face[0], face[1])] = true;}return result;}uint H1_homology_rank(ASC asc, uint N) {// dim im d_2F_2Vector[] d_2_matrix;auto edge_list = asc.edges.keys;foreach (face; asc.faces.keys) {F_2Vector vec;vec.set_entry(cast(uint) edge_list.countUntil(Edge(face[0], face[1])), 1);vec.set_entry(cast(uint) edge_list.countUntil(Edge(face[0], face[2])), 1);vec.set_entry(cast(uint) edge_list.countUntil(Edge(face[1], face[2])), 1);d_2_matrix ~= vec;}auto b_rank = get_rank(d_2_matrix);F_2Vector[] d_1_matrix;foreach (edge; asc.edges.keys) {F_2Vector vec;vec.set_entry(edge[0], 1);vec.set_entry(edge[1], 1);d_1_matrix ~= vec;}auto z_rank = cast(uint)asc.edges.length - get_rank(d_1_matrix);assert(z_rank >= b_rank);return z_rank - b_rank;}void main() {auto MN = readln.split.to!(uint[]);auto N = MN[0], M = MN[1];uint[][] face_list;foreach (m; 0 .. M) {face_list ~= readln.split.to!(uint[]);}auto asc = create_normalized_asc(face_list, N);auto co = is_connected(asc, N);auto dim = H1_homology_rank(asc, N);auto lk = links(asc, N).map!(a => is_connected(a, N)).all!(a => a);if (!co) writeln("CO");else if (dim != 0) writeln("H1");else if (!lk) writeln("LK");else writeln("CM");}/*******************************************************************************************************************************************************/alias F_2Vector = ulong[39]; // 39 * 8 > 300static ulong_size = 8 * (ulong.sizeof);void set_entry(ref F_2Vector vector, uint n_th, int val) {if (val)vector[n_th / ulong_size] |= 1UL << n_th % ulong_size;elsevector[n_th / ulong_size] &= ~0UL - (1UL << (n_th % ulong_size));}bool is_zero(F_2Vector vector) {foreach (e; vector) if (e != 0) return false;return true;}F_2Vector slide_vector(F_2Vector vector) {F_2Vector slided;foreach (i; 0 .. vector.length - 1) {slided[i] = vector[i+1];}return slided;}// by sweep// vectors can changeuint get_rank(F_2Vector[] vectors ...) {if (vectors.all!(v => is_zero(v))) return 0;// make the left-most vector nonzerowhile (vectors.all!(v => v[0] == 0))vectors.each!((ref v) => v = slide_vector(v));while (vectors.all!(v => v[0] % 2 == 0))vectors.each!((ref v) => v[0] >>= 1);foreach (ref v; vectors) {if (v[0] % 2 != 0) {auto tmp = vectors[0];vectors[0] = v;v = tmp;}}// sweepingforeach (ref v; vectors[1 .. $]) {if (v[0] % 2 != 0)v[] ^= vectors[0][];}vectors[1 .. $].map!((ref v) => v[0] >>= 1);return 1 + get_rank(vectors[1 .. $]);}// Union-tree of {0, 1, ..., num-1}class UnionFind {size_t num;private size_t[] parent;private size_t[] rank;private size_t[] size_;this (size_t num) {this.num = num;parent.length = num;foreach (n; 0 .. num) parent[n] = n;rank.length = num;size_.length = num;}size_t root(size_t n) {assert(n < num);if (parent[n] == n) return n;else return parent[n] = root(parent[n]); // recursively set the root}bool is_same(size_t n, size_t m) {assert(n < num && m < num);return root(n) == root(m);}// false if already unitedbool unite(size_t n, size_t m) {assert(n < num && m < num);auto rn = root(n), rm = root(m);if (rn == rm) return false;// swap if necessary to force rank[rm] <= rank[rn]if (rank[rn] < rank[rm]) {auto tmp = rm;rm = rn;rn = tmp;}parent[rm] = rn;if (rank[rn] == rank[rm]) ++rank[rn];size_[rn] += size_[rm] + 1;return true;}size_t size(size_t n) {return size_[root(n)]+1;}size_t size() {size_t result;foreach (i; 0 .. num)if (root(i) == i) result += 1;return result;}}