結果
問題 | No.3031 曲面の向き付け |
ユーザー |
![]() |
提出日時 | 2025-02-01 16:54:45 |
言語 | D (dmd 2.109.1) |
結果 |
AC
|
実行時間 | 335 ms / 2,000 ms |
コード長 | 3,579 bytes |
コンパイル時間 | 963 ms |
コンパイル使用メモリ | 94,768 KB |
実行使用メモリ | 61,740 KB |
最終ジャッジ日時 | 2025-02-01 22:01:52 |
合計ジャッジ時間 | 7,439 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 29 |
ソースコード
import std.algorithm, std.array, std.conv, std.stdio, std.typecons;class Triangle {uint A, B, C;Triangle nAB, nBC, nAC; // the triangles that share the edgesint orientation;this (uint a, uint b, uint c) {A = a, B = b, C = c;assert(A < B && B < C);}// false if already setvoid set_neighborhood(Triangle n, uint P, uint Q) {if (tuple(P, Q) == tuple(A, B)) {nAB = n;}else if (tuple(P, Q) == tuple(B, C)) {nBC = n;}else if (tuple(P, Q) == tuple(A, C)) {nAC = n;}else assert(0);}// X is A, B or C// 1: A->B->C, -1: A->C->Buint perm(uint X, int o = 0) {if (o == 0) o = this.orientation;if (o == 1) {if (X == A) return B;else if (X == B) return C;else if (X == C) return A;else assert(0);}else if (o == -1) {if (X == B) return A;else if (X == C) return B;else if (X == A) return C;else assert(0);}else assert(0);}}class Triangulation {Triangle[] triangles;bool unorientable = false;this(uint[][] tri_array) {// remove multiple appearancebool[Tuple!(uint, uint, uint)] triangle_set;foreach (tri3; tri_array) {triangle_set[tuple(tri3[0], tri3[1], tri3[2])] = true;}this.triangles = triangle_set.keys.map!(t => new Triangle(t[0], t[1], t[2])).array;// set neighborhoodsTriangle[Tuple!(uint, uint)] edges;uint[Tuple!(uint, uint)] edge_appear_times;foreach (triangle; triangles) {foreach (edge; [tuple(triangle.A, triangle.B), tuple(triangle.B, triangle.C), tuple(triangle.A, triangle.C)]) {if (auto neiborhood = edge in edges) {// shared by three trianglesif (edge_appear_times[edge] >= 2) {unorientable = true;return;}// set neighborhoodsedge_appear_times[edge]++;triangle.set_neighborhood(*neiborhood, edge[0], edge[1]);neiborhood.set_neighborhood(triangle, edge[0], edge[1]);}else {// set neighborhoodsedges[edge] = triangle;edge_appear_times[edge] = 1;}}}}// DFSvoid give_orientation(Triangle triangle, uint P, uint Q) {// already setif (!triangle || triangle.orientation != 0) return;triangle.orientation = triangle.perm(P, 1) == Q ? 1 : -1;// recursivelyif (triangle.perm(triangle.A) == triangle.B)give_orientation(triangle.nAB, triangle.B, triangle.A);elsegive_orientation(triangle.nAB, triangle.A, triangle.B);if (triangle.perm(triangle.B) == triangle.C)give_orientation(triangle.nBC, triangle.C, triangle.B);elsegive_orientation(triangle.nBC, triangle.B, triangle.C);if (triangle.perm(triangle.A) == triangle.C)give_orientation(triangle.nAC, triangle.C, triangle.A);elsegive_orientation(triangle.nAC, triangle.A, triangle.C);}bool is_orientable() {if (unorientable) return false;foreach (triangle; triangles) {give_orientation(triangle, triangle.A, triangle.B);}// checkforeach (triangle; triangles) {with (triangle)// A -> B -> C -> Aif (orientation == 1) {if ((nAB && nAB.perm(B) != A) || (nBC && nBC.perm(C) != B) || (nAC && nAC.perm(A) != C)) return false;}// A -> C -> B -> Aelse if (orientation == -1) {if ((nAB && nAB.perm(A) != B) || (nBC && nBC.perm(B) != C) || (nAC && nAC.perm(C) != A)) return false;}else assert (0);}return true;}}void main() {auto M = readln[0 .. $-1].to!uint;uint[][] tris;foreach (m; 0 .. M)tris ~= readln.split.to!(uint[]);auto trig = new Triangulation(tris);writeln(trig.is_orientable ? "YES" : "NO");}