trie图(AC自动机模板)

#include

using namespace std;

const int maxn = 1010;
int root, tot;
int que[maxn], head, tail;
int dp[maxn][maxn];

char str[maxn];

struct Node
{
int flag;
int fail;
int next[4];
void init()
{
flag = 0;
fail = -1;
memset(next, -1, sizeof(next));
}
}s[maxn];

void init()
{
root = tot = 0;
s[root].init();
}

int change( char ch )
{
if( ch== 'A' )
return 0;
if( ch== 'T' )
return 1;
if( ch== 'G' )
return 2;
else
return 3;
}

void insert(char * str)
{
int i;
int p = root, index;
int len = strlen(str);
for(i = 0; i < len; i++)
{
//index = s[i] - 'a';
index = change(str[i]);
if(s[p].next[index] == -1)
{
s[++tot].init();
s[p].next[index] = tot;
}
p = s[p].next[index];
}
s[p].flag = 1;
}

void build_ac_auto()
{
int u, i, p, son;
head = tail = 0;
que[tail++] = root;
while(head < tail)
{
u = que[head++];
for(i = 0; i < 4; i++)//如果儿子节点存在的话
{
if(s[u].next[i] != -1)//如果儿子节点存在的话
{
p = s[u].fail;//p指向父节点的前缀指针
son = s[u].next[i];//son(儿子节点,即当前节点)指向队首元素(父节点)的下一个节点(儿子节点)
while(p != -1 && s[p].next[i] == -1)//一直寻找前缀节点
p = s[p].fail;
if(u == root)//如果父节点为根节点则son的前缀指针指向根,即树中第二层的元素
s[son].fail = root;
else//否则的话son的前缀指针指向
s[son].fail = s[p].next[i];
if(s[s[son].fail].flag)
s[son].flag = 1;//这个题中的ac自动机模板加了这一句话来保证状态
que[tail++] = son;//保证层次遍历,将这个son节入队
}
//其实虚拟节点只在是根节点的时候加入,而当不是根节点时即为所建的虚拟边(那篇trie图的论文里的那个图中的蓝色边)
else//trie图,设定虚拟节点//当不为root节点时就是论文中所论述的“如果它的父结点的后缀结点w没有c孩子怎么办呢”
{
p = s[u].fail;//p指向父亲节点的前缀指针
while(p != -1 && s[p].next[i] == -1)//一直寻找前缀节点
p = s[p].fail;
if(u == root)//如果队首元素是根节点的话,则建立虚拟节点指向根(见北大字符串匹配的那个ppt)
s[u].next[i] = root;
else//如果不是队首元素的话,建立虚拟边,即“我们把需要新建的从w指向x的边直接指向x的后缀结点,即w

结点的后缀结点的c孩子即可”
s[u].next[i] = s[p].next[i];
}
}
}
}

void solve()
{
int i, j, k, len, t, ans;
len = strlen(str);
for(i = 0; i <= len; i++)
for(j = 0; j <= tot; j++)
dp[i][j] = INT_MAX;
dp[0][0] = 0;
for(i = 1; i <= len; i++)
{
for(j = 0; j <= tot; j++)
{
if(dp[i - 1][j] != INT_MAX && !s[j].flag)
{
for(k = 0; k < 4; k++)
{
if(!s[s[j].next[k]].flag)
{
t = s[j].next[k];
dp[i][t] = min(dp[i][t], dp[i - 1][j] + (k != change(str[i - 1])));
}
}
}
}
}
ans = INT_MAX;
for(i = 0; i <= tot; i++)
if(ans > dp[len][i])
ans = dp[len][i];
if(ans == INT_MAX)
printf("-1\n");
else
printf("%d\n", ans);
}

int main()
{
//freopen("C:\\Users\\Administrator\\Desktop\\1.txt","r",stdin);
int n, i;
int cas = 0;
while(scanf("%d", &n), n)
{
init();
for(i = 1; i <= n; i++)
{
scanf("%s", str);
insert(str);
}
build_ac_auto();
scanf("%s", str);
cas++;
printf("Case %d: ",cas);
solve();
}
return 0;
}

相关文档
最新文档