传送门
解题思路
先用字典树存储所有的字符串,然后对每个字符串进行判断是否能成为符合要求的字符串:
对于这个字符串的每一位,如果这一位上有别的字符串与之不同,那么一定就把别的字符串这一位上对应的字符j向这个字符串这一位上对应的字符t连一条边,表示我们规定的字母表中j大于t。
然后判断有没有环出现即可。
注意dfs要每查一次要清空(代码中),否则会挂,比如A->B,A->B->C。
当然拓扑也行……
AC代码
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<iomanip> 5 #include<cmath> 6 using namespace std; 7 const int maxn=30005; 8 string s[maxn]; 9 int ch[maxn*10][30],vis[maxn*10],cnt=1,n,en[maxn*10],num,ans[maxn]; 10 bool dayu[30][30],vis3[30]; 11 void insert(int id){ 12 int len=s[id].length(),now=1; 13 for(int i=0;i<len;i++){ 14 if(!ch[now][s[id][i]-'a']) ch[now][s[id][i]-'a']=++cnt; 15 now=ch[now][s[id][i]-'a']; 16 vis[now]++; 17 } 18 en[now]++; 19 } 20 bool dfs(int u){ 21 if(vis3[u]) return 0; 22 vis3[u]=1; 23 for(int i=0;i<=25;i++){ 24 if(u==i) continue; 25 if(!dayu[u][i]) continue; 26 if(!dfs(i)) return 0; 27 } 28 vis3[u]=0;//注意 29 return 1; 30 } 31 bool query(int id){ 32 memset(dayu,0,sizeof(dayu)); 33 memset(vis3,0,sizeof(vis3)); 34 int len=s[id].length(),now=1; 35 for(int i=0;i<len;i++){ 36 if(en[now]) return 0; 37 int t=s[id][i]-'a'; 38 for(int j=0;j<=25;j++){ 39 if((j!=t)&&ch[now][j]){ 40 if(dayu[t][j]) return 0; 41 else dayu[j][t]=1; 42 } 43 } 44 now=ch[now][s[id][i]-'a']; 45 if(vis[now]==1) break; 46 } 47 for(int i=0;i<=25;i++) if(!vis3[i]&&!dfs(i)) return 0; 48 return 1; 49 } 50 int main(){ 51 cin>>n; 52 for(int i=1;i<=n;i++){ 53 cin>>s[i]; 54 insert(i); 55 } 56 for(int i=1;i<=n;i++){ 57 if(query(i)) ans[++num]=i; 58 } 59 cout<<num<<endl; 60 for(int i=1;i<=num;i++) cout<<s[ans[i]]<<endl; 61 return 0; 62 }