每根木棍兩端有顏色,視為無向圖的邊;顏色視為頂點。問題轉化為:給定無向圖,是否存在歐拉通路(恰好走過每條邊一次,可不回到起點)。
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
const int MAXN = 500005; // 最大節點數:邊數×2
const int SIGMA = 26;
struct Trie {
int sz;
int g[MAXN][SIGMA];
int val[MAXN]; // 節點對應的頂點 ID(0 表未分配)
void init() {
sz = 1; val[0] = 0;
memset(g[0], 0, sizeof(g[0]));
}
int idx(char ch) { return ch - 'a'; }
int insert(const char* s) {
int u = 0, n = strlen(s);
for (int i = 0; i < n; ++i) {
int v = idx(s[i]);
if (!g[u][v]) {
g[u][v] = sz;
memset(g[sz], 0, sizeof(g[sz]));
val[sz++] = 0;
}
u = g[u][v];
}
if (!val[u]) { // 首次出現,分配新 ID
val[u] = ++N;
fa[N] = N;
deg[N] = 0;
}
return val[u];
}
} T;
int N, E;
int fa[MAXN], deg[MAXN];
pair edges[MAXN];
int findFa(int x) { return x == fa[x] ? x : fa[x] = findFa(fa[x]); }
bool check() {
// 1. 奇度數檢查
int odd = 0;
for (int i = 1; i <= N; ++i) if (deg[i] & 1) ++odd;
if (odd > 2) return false;
// 2. 連通性檢查:用邊列表二次合併並查集
int comp = N;
for (int i = 0; i < E; ++i) {
int u = findFa(edges[i].first);
int v = findFa(edges[i].second);
if (u != v) { fa[u] = v; --comp; }
}
return comp <= 1; // 所有有邊頂點在同一分量
}
int main() {
T.init();
N = E = 0;
char a[11], b[11];
while (scanf("%s%s", a, b) == 2) {
int u = T.insert(a);
int v = T.insert(b);
++deg[u]; ++deg[v];
edges[E++] = {u, v};
}
puts(check() ? "Possible" : "Impossible");
return 0;
}
設 V 為顏色種類數,E 為木棍數。
• 字典樹插入:O(E × L),L ≤ 10。
• 並查集操作:O(E α(V))。
• 總時間 O(E),空間 O(V + E),極高效率。