kafka叢集部署
Trie樹 上拓撲。
為什麼這道題目要建立 Trie樹 呢...因為對於兩個字串,比較他們的字典序大小無非就是比較他們第一個相當的字元是什麼,也就是說,如果這兩個字串在第 \(k\) 位開始不一樣,那麼他們也會在 \(k\) 對應的節點分別走向 \(k\) 不同的兒子。
暴力的思路無非就是暴力列舉、暴力判斷吧...列舉應該是不能優化了(?),而判斷可以藉助 Trie樹 來優化判斷呀。存在大小關係...是不是可以將大小關係變為一個有向圖呢?如果這個字元不可能是解的話,一定存在一組字元 \(u\) 和 \(v\) 使得 \(u\) 既要優先於 \(v\) ,\(v\) 也要優先與 \(u\)...
對於一個字串,我們先假定這個字串是字典序最小的,那麼是不是就可以確定每個字元之間的大小關係呢...所以我們可以對於這個欽定的字串 \(s\) 的每一位對應的 Trie樹 上的節點 \(id\) ,遍歷 \(id\) 的每一個子結點(因為 Trie樹 上並沒有記錄每個點存在的子結點有幾個,所以只能 \(0\) 至 \(25\) 來列舉),如果這個子結點有不同於 \(s\) 這一位的字元 \(j\) ,並且 \(id\) 存在 \(j\) 這個兒子,並且 \(tmp\) 暫時沒有與 \(j\) 確定大小關係,那麼很明顯 \(tmp\) 是要優先於 \(j\) 的 ,因此 \(tmp\) 向 \(j\)
很顯然,如果存在一個可以的排列的話,這個有向圖一定是一個 DAG !每個字元都存在一個固定字元排在它的前一位...
於是通過這個迴圈,我們確定了優先順序...
ll id=0,len=x.length(); memset(e,0,sizeof(e)); memset(in,0,sizeof(in)); for(register int i=0;i<len;++i){ if(ed[id]) return 0; ll tmp=x[i]-'a'; for(register int j=0;j<26;++j) if(tmp!=j&&trie[id].ch[j]&&!e[tmp][j]){ e[tmp][j]=1; ++in[j]; } id=trie[id].ch[tmp]; }
如何判斷是不是 DAG 呢...拓撲排序啊。
如果一個點始終不能將入度變為 \(0\) ,說明這個有向圖是存在環的!這樣就很好判斷了呀~如果存在環說明一定存在一個 \(u\) 和一個 \(v\) 使得 \(u\) 要優先於 \(v\) 而 \(v\) 也要優先於 \(u\)!
至此,這道題目就做完了呀...
拓撲排序:
queue<ll>q;
while(!q.empty()) q.pop();
for(register int i=0;i<26;++i)
if(!in[i])
q.push(i);
while(!q.empty()){
ll u=q.front();q.pop();
for(register int i=0;i<26;++i)
if(e[u][i]){
--in[i];
if(!in[i])
q.push(i);
}
}
判斷是否為 DAG:
for(register int i=0;i<26;++i)
if(in[i])
return 0;
return 1;
完整程式:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,cnt,node,ed[400001],in[30],ans,e[30][30],ok[30001];
string s[30001],c;
struct Node{
ll fail=0,num=0,ch[25];
}trie[400001];
inline ll read(){
ll x=0,f=0;char c=getchar();
while(!isdigit(c)) f|=c=='-',c=getchar();
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
return f?-x:x;
}
inline void build(ll x){
ll id=0,len=s[x].length();
for(register int i=0;i<len;++i){
ll tmp=s[x][i]-'a';
if(!trie[id].ch[tmp])
trie[id].ch[tmp]=++cnt;
id=trie[id].ch[tmp];
}
ed[id]=1;
}
inline int find(string x){
ll id=0,len=x.length();
memset(e,0,sizeof(e));
memset(in,0,sizeof(in));
for(register int i=0;i<len;++i){
if(ed[id]) return 0;
ll tmp=x[i]-'a';
for(register int j=0;j<26;++j)
if(tmp!=j&&trie[id].ch[j]&&!e[tmp][j]){
e[tmp][j]=1;
++in[j];
}
id=trie[id].ch[tmp];
}
queue<ll>q;
while(!q.empty()) q.pop();
for(register int i=0;i<26;++i)
if(!in[i])
q.push(i);
while(!q.empty()){
ll u=q.front();q.pop();
for(register int i=0;i<26;++i)
if(e[u][i]){
--in[i];
if(!in[i])
q.push(i);
}
}
for(register int i=0;i<26;++i)
if(in[i])
return 0;
return 1;
}
int main(){
n=read();
for(register int i=1;i<=n;++i){
cin>>s[i];
build(i);
}
for(register int i=1;i<=n;++i)
if(find(s[i])){
++ans;
ok[i]=1;
}
printf("%lld\n",ans);
for(register int i=1;i<=n;++i)
if(ok[i])
cout<<s[i]<<endl;
return 0;
}