[树形dp][trie]cf856B Similar Words

来源:互联网 发布:家里有网络怎么看电视 编辑:程序博客网 时间:2024/06/16 02:12

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 integer n — the number of words in the set S(1n106). Each of the following n lines contains one non-empty word — elements of S. All words in S 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 — 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;}