题目链接:SPOJ7758
MGLAR10 - Growing Strings
English | Vietnamese |
Input
Each test case is given using several lines. The first line contains an integer N representing the number of strings in the set (1 ≤ N ≤ 10^4). Each of the following N lines contains a different non-empty string of at most 1000 lowercase letters of the English alphabet. Within each test case, the sum of the lengths of all strings is at most 10^6.
The last test case is followed by a line containing one zero.
Output
For each test case output a single line with a single integer representing the size of the largest sequence of photos that can be produced.
Sample
input
6 plant ant cant decant deca an 2 supercalifragilisticexpialidocious rag 0
output
4 2
题目分析:SPOJ的账号申请半天,结果一直都是申请失败,不知道为啥,,,而且网上题解少的可怜,,白瞎这么好的题了。。。。
这题主要考察AC自动机和DP,先要把每个字符串加入字典树,作为标记末尾节点的num为1。然后构造fail指针。不过仔细考察fail指针的意义就会发现我们可以在构造fail指针的时候顺便就能把答案求出来。每个fail指针指向这个字符串的最长后缀的位置。我们在每个字典树的每个节点上加一个整型sum作为以从root到这个节点的字符串为最右面的字符串时左面最多能有多少字符串(这里如果这个字符串是完整的话就把自己也加上,否则的话不用)。
这样就比较明了了。只需取其的父节点p的sum值和p->next[i]->fail节点的sum值的最大项加上自己的num即可。状态转移方程p->next[i]->sum=max(p->sum,p->next[i]->fail->sum)+p->next[i]->num;每求出一个sum都和ans取最大值。构造完fail指针这题也差不多了。
//
// main.cpp
// SPOJ7758
//
// Created by teddywang on 16/4/11.
// Copyright © 2016年 teddywang. All rights reserved.
//
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,ans,num,ptr,head,tail;
typedef struct node{
int flag;
int num,sum;
node *next[26];
node *fail;
}trienode;
trienode *root;
trienode *qu[1000006];
trienode *creat_node()
{
trienode *r=new node;
r->num=r->flag=r->sum=0;
for(int i=0;i<26;i++)
r->next[i]=NULL;
r->fail=NULL;
return r;
}
void init()
{
root=creat_node();
ans=num=ptr=0;
head=tail=0;
}
void insert_node(char *s)
{
trienode *r=root,*t;
int len=strlen(s);
for(int i=0;i<len;i++)
{
int buf=s[i]-'a';
if(r->next[buf]==NULL)
{
t=creat_node();
r->next[buf]=t;
r=t;
}
else r=r->next[buf];
}
r->flag=1;r->num=1;
}
void build_ac()
{
qu[head++]=root;
while(tail<head)
{
trienode *p=qu[tail++];
for(int i=0;i<26;i++)
{
if(p->next[i]!=NULL)
{
if(p==root)
p->next[i]->fail=root;
else
{
trienode *temp=p->fail;
while(temp!=NULL)
{
if(temp->next[i]!=NULL)
{
p->next[i]->fail=temp->next[i];
break;
//p->next[i]->num+=temp->next[i]->num;
}
else temp=temp->fail;
}
if(temp==NULL) p->next[i]->fail=root;
}
p->next[i]->sum=max(p->sum,p->next[i]->fail->sum)+p->next[i]->num;
ans=max(ans,p->next[i]->sum);
qu[head++]=p->next[i];
}
}
}
}
void del(trienode *p)
{
for(int i=0;i<26;i++)
{
if(p->next[i]!=NULL)
{
del(p->next[i]);
}
}
free(p);
}
int main()
{
while(cin>>n&&n)
{
init();
for(int i=0;i<n;i++)
{
char s[2005];
scanf("%s",s);
insert_node(s);
}
ans=0;
build_ac();
cout<<ans<<endl;
del(root);
}
}
注意要释放内存。