1. 程式人生 > >Kattis taboo (AC自動機 拓撲排序 DP)

Kattis taboo (AC自動機 拓撲排序 DP)

題意:給出n個01串,要構造一個最長的串使得這個串不包含所有出現過的串,無解輸出-1.

首先把所有的點扔進自動機,因為出現過的串不能在我們構造的串中出現,所以事先把某些”壞點”標記,壞點指的就是每個串的結束節點以及沿著結束節點fail指標走下去的節點. 如果剩下的圖中能夠沿著根走出一個環那麼必然就無解了, 判環可以用一遍拓撲確定. 排除無解情況剩下就是一個DAG了, 用dp[i][j]表示在自動機上i節點, 串長為j是否可行, 最後按照最長路列印方案即可.

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue> #include <cmath> #include <algorithm> #include <stack> #define Clear(x,y) memset (x,y,sizeof(x)) #define fi first #define se second #define pii pair<int, int> #define pli pair<long long, int> #define pb push_back #define mod 1000000007 template <class
T> inline bool scan (T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return 0; //EOF while (c != '-' && (c < '0' || c > '9') ) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0' && c <= '9'
) ret = ret * 10 + (c - '0'); ret *= sgn; return 1; } using namespace std; #define maxn 500005 int G[maxn][2]; void add_edge (int u, int v, int w) { G[u][w] = v; } struct trie { int next[maxn][2], fail[maxn]; long long end[maxn]; int root, cnt; int new_node () { memset (next[cnt], -1, sizeof next[cnt]); end[cnt++] = 0; return cnt-1; } void init () { cnt = 0; root = new_node (); } void insert (char *buf) {//字典樹插入一個單詞 int len = strlen (buf); int now = root; for (int i = 0; i < len; i++) { int id = buf[i]-'0'; if (next[now][id] == -1) { next[now][id] = new_node (); } now = next[now][id]; if (end[now]) break; } end[now]++; } void build () {//構建fail指標 queue <int> q; fail[root] = root; for (int i = 0; i < 2; i++) { if (next[root][i] == -1) { next[root][i] = root; } else { fail[next[root][i]] = root; q.push (next[root][i]); } } while (!q.empty ()) { int now = q.front (); q.pop (); end[now] += end[fail[now]]; for (int i = 0; i < 2; i++) { if (next[now][i] == -1) { next[now][i] = next[fail[now]][i]; } else { fail[next[now][i]] = next[fail[now]][i]; q.push (next[now][i]); } } } } int in[maxn], in2[maxn]; bool vis[maxn], inq[maxn]; void dfs1 (int u) { for (int id = 0; id < 2; id++) { int j = next[u][id]; if (end[j]) continue; in[j]++; in2[j]++; if (in[j] == 1) dfs1 (j); } } bool topo () {///判環 Clear (inq, 0); Clear (vis, 0); Clear (in, 0); Clear (in2, 0); int tot = 0, num = 0; dfs1 (0); queue <int> q; while (!q.empty ()) q.pop (); if (in[0]) return 1; inq[0] = 1, vis[0] = 1; q.push (0); num++; while (!q.empty ()) { int u = q.front (); q.pop (); for (int id = 0; id < 2; id++) { int v = next[u][id]; if (end[v]) continue; in[v]--; vis[v] = 1; if (!in[v]) { q.push (v); inq[v] = 1; num++; } } } for (int i = 0; i < cnt; i++) { if (inq[i] != vis[i]) { return 1; } } return 0; } int dp[maxn], to[maxn], Max; int pre[maxn]; void dfs (int u) { for (int id = 0; id < 2; id++) { int v = next[u][id]; if (end[v]) continue; dfs (v); to[u] = max (to[u], to[v]+1); if (to[v]+dp[u]+1 == Max) { add_edge (u, v, id); } } } void query () { if (topo ()) { printf ("-1\n"); return ; } Clear (dp, 0); queue <int> q; while (!q.empty ()) q.pop (); q.push (0); Max = 0; while (!q.empty ()) { int u = q.front (); q.pop (); for (int id = 0; id < 2; id++) { int j = next[u][id]; if (end[j]) continue; if (dp[j] < dp[u]+1) { dp[j] = dp[u]+1; } in2[j]--; if (!in2[j]) { q.push (j); Max = max (Max, dp[j]); } } } Clear (G, -1); Clear (to, 0); dfs (0); int u = 0; while (dp[u] != Max) { if (G[u][0] != -1) { printf ("0"); u = G[u][0]; } else { printf ("1"); u = G[u][1]; } } printf ("\n"); } }ac; int n; char buf[maxn]; int main () { scanf ("%d", &n); ac.init (); for (int i = 0; i < n; i++) { scanf ("%s", buf); ac.insert (buf); } ac.build (); ac.query (); return 0; }