給定 n 個病毒代碼片段(01串,總長 ≤ 30000)。若一個二進制串不包含任一病毒片段作為子串,則稱其為「安全的」。問:是否存在無限長的安全串?存在輸出 TAK,否則 NIE。
danger[u] |= danger[fail[u]](若失配祖先是危險的,則當前節點也危險)存在無限長安全串 ⇔ 非危險節點構成的有向圖中存在環。
證明:
TAK;否則 NIE// AC自動機構建(同標準 BFS)
void build_ac() {
queue q; q.push(1);
while (!q.empty()) {
int u = q.front(); q.pop();
danger[u] |= danger[fail[u]]; // 傳遞危險標記
for (int c = 0; c < 2; ++c) {
if (trie[u][c]) {
fail[trie[u][c]] = trie[fail[u]][c];
q.push(trie[u][c]);
} else {
trie[u][c] = trie[fail[u]][c];
}
}
}
}
// 拓撲排序檢測環
bool has_infinite_safe() {
vector in(tot + 1, 0);
// 建圖並統計入度(僅非危險節點)
for (int u = 1; u <= tot; ++u) {
if (danger[u]) continue;
for (int c = 0; c < 2; ++c) {
int v = trie[u][c];
if (!danger[v]) {
in[v]++;
}
}
}
// 拓撲排序
queue q;
int cnt = 0;
for (int u = 1; u <= tot; ++u) {
if (!danger[u] && in[u] == 0) q.push(u);
}
while (!q.empty()) {
int u = q.front(); q.pop();
cnt++;
for (int c = 0; c < 2; ++c) {
int v = trie[u][c];
if (!danger[v] && --in[v] == 0) q.push(v);
}
}
// 統計非危險節點總數
int safe_total = 0;
for (int u = 1; u <= tot; ++u) if (!danger[u]) safe_total++;
return cnt < safe_total; // 有環
}
danger[u] |= danger[fail[u]] 必須在 BFS 中按層序執行,保證祖先先處理trie[u][c] = trie[fail[u]][c] 確保圖完整TAK(波蘭語「是」),無環 → NIE(波蘭語「否」)