1. 程式人生 > >AC自動機+DP泛做

AC自動機+DP泛做

fail inline 代碼 memset 加密 char mat code cpp

情報加密

題意:給定\(n\)個字符串\(n(1<=n<=50)\)個長度小於&20&的模式串。在給定一個長度小於\(1000\)的字符串\(T\)
求最少改變多少個\(T\)中的字符,使得\(T\)中不包含\(n\)個模式串。

AC代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define min(a, b) (a < b ? a : b)
const int CHA = 4;
const int MAXN = 1000
; const int INF = 0x3f3f3f3f; using namespace std; struct AcAutoMaton { int tot, trie[MAXN + 5][4], fail[MAXN + 5], dp[MAXN + 5][MAXN + 5]; bool val[MAXN + 5]; queue < int > Q; AcAutoMaton() { tot = 0; } void insert(char *P) { int l = strlen(P), now = 0
; for (int i = 0; i < l; ++i) { int c = P[i] - ‘A‘; if (!trie[now][c]) trie[now][c] = ++tot; now = trie[now][c]; } val[now] = true; } void getFail() { for (int i = 0; i < CHA; ++i) { int u = trie[0
][i]; if (u) { fail[u] = 0; Q.push(u); } } while (!Q.empty()) { int cur = Q.front(); Q.pop(); for (int i = 0; i < CHA; ++i) { int u = trie[cur][i]; if (u) { fail[u] = trie[fail[cur]][i]; val[u] |= val[fail[u]]; Q.push(u); } else trie[cur][i] = trie[fail[cur]][i]; } } } int query(char *T) { int l = strlen(T); memset(dp, 0x3f, sizeof(dp)); dp[0][0] = 0; for (int i = 1; i <= l; ++i) for (int j = 0; j <= tot; ++j) for (int k = 0; k < CHA; ++k) { int u = trie[j][k]; if (!val[u]) { if (T[i - 1] - ‘A‘ == k) dp[i][u] = min(dp[i][u], dp[i - 1][j]); else dp[i][u] = min(dp[i][u], dp[i - 1][j] + 1); } } int ret = INF; for (int j = 0; j <= tot; ++j) ret = min(ret, dp[l][j]); return ret == INF ? -1 : ret; } }AC; int n; char P[20 + 5]; void init() { scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%s", P); AC.insert(P); } AC.getFail(); } char T[1000 + 5]; int main() { init(); scanf("%s", T); printf("%d\n", AC.query(T)); return 0; }

AC自動機+DP泛做