http://acm.zjnu.edu.cn/CLanguage/contests/1167/problems/1002.html
(当校のOJで提出できます)
題名
間違っている可能性のある三角形分割(次数nの凸多角形、内部n-3対角)を入力します。
各エッジのエッジの重みは3色のいずれかです。
検証1:これは正しい三角形分割です
検証2:この三角形分割の各単位三角形は異色三角形です。
アイデア
三角形分割が正しい場合、内側の各要素の三角形の内角はエッジに対応します。
(逆に、対角線は2つの内角に対応し、輪郭エッジは1つの内角に対応します。)
接続エラーがある場合、内部ポリゴンは三角形ではないことにバインドされます。これにより、内隅に対応する辺が見つかりません。
各三角形が異色三角形である場合、各内角の2つの角は異なる色になります。
したがって、内側のコーナーを列挙し、各内側のコーナー、反対側が存在するかどうか、含まれているコーナーの色が異なるかどうかを確認します。
内側のコーナーを列挙する方法は?
この幾何学的図形を無向グラフ理論モデルに組み込むには、各点の隣接リストの数値が時計回りまたは反時計回りであることを期待し、次に列挙された各隣接エッジが図の内角を表します。
隣接リストをソートするときは、現在の数を最小値として考慮し、すべての数を再マッピングします(モジュロ)。このように、並べ替え後、n-1から自然に列挙でき、次は0 1 2です。
次は反時計回りの並べ替え方法です:
ラムダを理解せず、比較関数を記述して、iをグローバル変数として渡すことができます。
for (int i = 0; i < n; ++i) {
sort(g[i].begin(), g[i].end(), [&i](edge l, edge r) {
return (l.id - i + n) % n < (r.id - i + n) % n;
});
}
コード
const int MAXN = 2e5 + 59;
using pii = pair<int, int>;
int n;
char s[MAXN];
vector<pii> g[MAXN];
set<pii> has;
void solve(int kaseId = -1) {
int _ = 0;
cin >> _;
cin >> n >> s;
bool check1 = true;
bool check2 = true;
for (int i = 0; i < n - 3; ++i) {
int u, v, c;
cin >> u >> v >> c;
u--, v--;
g[u].emplace_back(v, c);
g[v].emplace_back(u, c);
has.emplace(u, v);
}
for (int i = 0; i < n; ++i) {
int u = i;
int v = (i + 1) % n;
int c = s[i] - '0';
g[u].emplace_back(v, c);
g[v].emplace_back(u, c);
}
for (int i = 0; i < n; ++i) {
sort(g[i].begin(), g[i].end(), [&i](pii l, pii r) {
return (l.first - i + n) % n < (r.first - i + n) % n;
});
}
for (int u = 0; check1 && u < n; ++u) {
int len = int(g[u].size());
for (int i = 0, j = 1; j < len; ++i, ++j) {
int vi = g[u][i].first;
int vj = g[u][j].first;
int ci = g[u][i].second;
int cj = g[u][j].second;
if ((vi + 1) % n != vj &&
(vj + 1) % n != vi && // 轮廓边必然存在,跳过。
has.count(pii{
vi, vj}) == 0 &&
has.count(pii{
vj, vi}) == 0) {
check1 = false;
break;
}
if (ci == cj) {
check2 = false;
}
}
}
if (!check1) {
cout << "neispravna triangulacija\n";
} else if (!check2) {
cout << "neispravno bojenje\n";
} else {
cout << "tocno\n";
}
}