AC自動機+DP泛做
阿新 • • 發佈:2018-05-03
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泛做