Description
Let us call a non-empty sequence of lowercase English letters a word. Prefix of a word x is a word y that can be obtained from x by removing zero or more last letters of x.
Let us call two words similar, if one of them can be obtained from the other by removing its first letter.
You are given a set S of words. Find the maximal possible size of set of non-empty words X such that they satisfy the following:
- each word of X is prefix of some word from S;
- X has no similar words.
Input
Input data contains multiple test cases. The first line of the input data contains an integer t — the number of test cases. The descriptions of test cases follow.
The first line of each description contains an integern — the number of words in the set S(1 ≤ n ≤ 106 ). Each of the following n lines contains one non-empty word — elements of S . All words inS are different.
It is guaranteed that the total length of all words in one input data doesn’t exceed 106 .
Output
For each test case print one line that contains one integer m <script type="math/tex" id="MathJax-Element-7">m</script> — the maximal number of words that X can contain.
Sample Input
2
3
aba
baba
aaab
2
aa
a
Sample Output
6
1
在一棵树上,相邻的点不能同时取,问最多取多少个点。
dp[i][0]代表不取本点,子树的答案,dp[i][1]代表取,树形dp采用dfs实现即可。
树的构造过程为similiar words之间连边。至于为什么形成的是树,可以采用反证法证明没有偶环(最长的前缀只能连接一个similar word),而奇环显然不存在。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
const int maxm = 26;
int tot, n;
int ch[maxn][maxm];
int newNode()
{
memset(ch[tot], 0, sizeof ch[tot]);
return tot++;
}
char s[maxn];
void add(char *s)
{
int len = strlen(s);
int cur = 0;
for(int i = 0; i < len; ++ i)
{
int v = s[i] - 'a';
if(ch[cur][v] == 0) ch[cur][v] = newNode();
cur = ch[cur][v];
}
}
string str[maxn];
vector<int> G[maxn];
void buildGraph(const string &s)
{
int a = 0;
int b = ch[0][s[0]-'a'];
for(int i = 1; i < s.size(); ++ i)
{
int v = s[i] - 'a';
a = ch[a][v];
b = ch[b][v];
if(a == 0 || b == 0) return;
G[a].push_back(b);
G[b].push_back(a);
}
}
int f[maxn][2];
bool vis[maxn];
void dfs(int u)
{
vis[u] = true;
f[u][0] = 0;
f[u][1] = 1;
for(auto v : G[u])
{
if(vis[v]) continue;
dfs(v);
f[u][0] += max(f[v][0], f[v][1]);
f[u][1] += f[v][0];
}
}
int main()
{
int T;
cin >> T;
while(T--)
{
tot = 1;
cin >> n;
memset(ch[0], 0, sizeof ch[0]);
for(int i = 0; i < n; ++ i)
{
scanf("%s", s);
add(s);
str[i] = s;
}
for(int i = 1; i < tot; ++ i) G[i].clear();
for(int i = 0; i < n; ++ i) buildGraph(str[i]);
for(int i = 1; i <= tot; ++ i) vis[i] = false;
int res = 0;
for(int i = 1; i < tot; ++ i)
{
if(!vis[i])
{
dfs(i);
res += max(f[i][0], f[i][1]);
}
}
cout << res << endl;
}
return 0;
}