Gene and Gina have a particular kind of farm. Instead of growing animals and vegetables, as it is usually the case in regular farms, they grow strings. A string is a sequence of characters. Strings have the particularity that, as they grow, they add characters to the left and/or to the right of themselves, but they never lose characters, nor insert new characters in the middle.
Gene and Gina have a collection of photos of some strings at different times during their growth. The problem is that the collection is not annotated, so they forgot to which string each photo belongs to. They want to put together a wall to illustrate strings growing procedures, but they need your help to find an appropriate sequence of photos.
Each photo illustrates a string. The sequence of photos must be such that if si comes immediately before si+1 in the sequence, then si+1 is a string that may have grown from si (i.e., si appears as a consecutive substring of si+1). Also, they do not want to use repeated pictures, so all strings in the sequence must be different.
Given a set of strings representing all available photos, your job is to calculate the size of the largest sequence they can produce following the guidelines above.
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
Added by: ~!((@!@^&
Date: 2010-11-05
Time limit: 0.519s-11.98s
Source limit: 50000B
Memory limit: 1536MB
Cluster: Cube (Intel Pentium G860 3GHz)
Languages: All except: SCM chicken
Resource: ACM ICPC2010 – Latin American Regional
AC自动机+DP
自动机上每一个节点,这个节点的最优值来自于2部分:父亲节点(前缀), fail指针(后缀)外加以这个节点结尾的字符串的个数
/************************************************************************* > File Name: spoj7758.cpp > Author: ALex > Mail: [email protected] > Created Time: 2015年02月06日 星期五 13时30分51秒 ************************************************************************/
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;
const int MAX_NODE = 1000010; //节点个数
const int CHUILD_NUM = 26;
char str[1110000];
int dp[1110000];
struct AC_Automation
{
int chd[MAX_NODE][CHUILD_NUM];
int end[MAX_NODE];
int fail[MAX_NODE];
queue <int> qu;
int sz;
int ID[500];
void Initialize()
{
fail[0] = 0; //root
for (int i = 0; i < CHUILD_NUM; ++i)
{
ID[i + 'a'] = i;
}
}
void Reset()
{
memset (chd, 0, sizeof(chd));
sz = 1;
}
void Build_Trie(char str[])
{
int p = 0;
int len = strlen (str);
for (int i = 0; i < len; ++i)
{
int c = ID[str[i]];
if (!chd[p][c])
{
memset (chd[sz], 0, sizeof(chd[sz]));
end[sz] = 0;
chd[p][c] = sz++;
}
p = chd[p][c];
}
++end[p];
}
void Build_AC()
{
int ans = 0;
while (!qu.empty())
{
qu.pop();
}
for (int i = 0; i < CHUILD_NUM; ++i)
{
if (chd[0][i])
{
fail[chd[0][i]] = 0;
qu.push (chd[0][i]);
dp[chd[0][i]] = end[chd[0][i]];
ans = max(ans, dp[chd[0][i]]);
}
}
while (!qu.empty())
{
int u = qu.front();
qu.pop();
for (int i = 0; i < CHUILD_NUM; ++i)
{
int &v = chd[u][i];
if (v)
{
qu.push(v);
fail[v] = chd[fail[u]][i];
dp[v] = max(dp[u], dp[fail[v]]) + end[v];
ans = max(ans, dp[v]);
}
else
{
v = chd[fail[u]][i];
}
}
}
printf("%d\n", ans);
}
}AC;
int main ()
{
int n;
while (~scanf("%d", &n), n)
{
AC.Reset();
AC.Initialize();
memset (dp, 0, sizeof (dp));
for (int i = 1; i <= n; ++i)
{
scanf("%s", str);
AC.Build_Trie(str);
}
AC.Build_AC();
}
return 0;
}