题目链接:SPOJ7758
English | Vietnamese |
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.
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.
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); } }