주제 링크
첫째, 우리는 여러 데이터의 문자열뿐만 아니라 공통의 접두사를 찾는를 입력, 생각하기 쉽습니다 되는이 질문에 (트리는 \) \ 응용 프로그램
우리는 \ (트리는 \) 나무 위에 지어진 나무에 달려 \ (DP \)가 될 수 있습니다.
즉 \ (DP (U, DIS) \) 로 표시 \은 (유 \) 서브 트리의 루트가, \ (U \) 깊이 \ (DIS \) 에 응답하면
쉽게 생각할 수있는 주체에 의해 정의 \ (DP (U, DIS) = 최대 \ {DIS TOT * [U], DP (V, DIS +. 1) \} \)
\ (TOT는 [U]는 \) 이다 (U \) \ 루트 서브 트리의 리프 노드의 수 (하기 즉, 루트 노드 (\ U \) 공통 접두어 기간, 공통 접두어를 갖는 문자열을 양 \ (TOT [U] \) )
그래서 우리는 차 코드를 기대할 수 있습니다 :
#include <bits/stdc++.h>
using namespace std;
struct Trie{
static const int maxnode = 100100;
static const int sigma_size = 2;
int ch[maxnode][sigma_size];
int val[maxnode];
int sz;
inline void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
Trie(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
inline int idx(char c){return c - '0';}
inline void insert(const string &s){
int u = 0,n = s.size();
for(int i = 0;i < n;i++){
int c = idx(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u]++;
}
inline int tot(int u){
int ret = val[u];
for(int c = 0;c < sigma_size;c++)
if(ch[u][c])ret += tot(ch[u][c]);
return ret;
}
inline int dfs(int u,int dis){
int ret = dis * tot(u);
for(int c = 0;c < sigma_size;c++)
if(ch[u][c])ret = max(ret,dfs(ch[u][c],dis + 1));
return ret;
}
}tt;
string ss;
int T,n;
inline void solve(){
tt.init();
cin >> n;
for(int i = 1;i <= n;i++){
cin >> ss;
tt.insert(ss);
}
printf("%d\n",tt.dfs(0,0));
}
int main(){
ios::sync_with_stdio(false);
cin >> T;
while(T--)
solve();
return 0;
}
실행 코드 160 밀리 , 시간이 초과되지 않습니다,하지만 우리는 여전히 최적화를 고려한다.
모든 \ (DP \)를 고려하는됩니다 \ (TOT \) , 시간 현장에서 복잡성 폭발 (데이터 무해한 H2O하지만).
그때
우리는 구축 할 수 있습니다 \ (트리는 \) 때 나무를 \ (TOT \) 배열을 알아낼 수 있습니다.
일반적으로 내장 \ (트리는는 \) 나무 잎 노드는이 질문에 가치 권한을 부여하는 것입니다, 모든 무게는 우리가 점하는 동안 성과가된다 넣어 \을 (+ 1 \) , 이 권리는 각 노드의 값입니다 서브 트리의 루트 노드의 리프 노드의 수
코드 :
#include <bits/stdc++.h>//懒得打了,大家最好别用万能头文件
using namespace std;
struct Trie{
static const int maxnode = 100100;//最大节点数
static const int sigma_size = 2;//字符集大小
int ch[maxnode][sigma_size];//儿子数组
int val[maxnode];//节点附加权值,即转移方程的tot数组
int sz;//当前节点总数
inline void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}//初始化函数
Trie(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
inline int idx(char c){return c - '0';}
inline void insert(const string &s){//插入字符串,传引用避免拷贝开销
int u = 0,n = s.size();
for(int i = 0;i < n;i++){
int c = idx(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
val[u]++;//这里即上文所说的统计子树节点个数
}
}
inline int dfs(int u,int dis){//最终答案
int ret = val[u] * dis;
for(int c = 0;c < sigma_size;c++)
if(ch[u][c])
ret = max(ret,dfs(ch[u][c],dis + 1));
return ret;
}
}tt;
string ss;
int T,n;
inline void solve(){//多组数据求解
tt.init();
cin >> n;
for(int i = 1;i <= n;i++){
cin >> ss;
tt.insert(ss);
}
printf("%d\n",tt.dfs(0,0));
}
int main(){
ios::sync_with_stdio(false);
cin >> T;
while(T--)
solve();
return 0;
}