牛客比赛-假的字符串-Trie+拓扑

链接:https://www.nowcoder.com/acm/contest/59/B
来源:牛客网

题目描述

给定n个字符串,互不相等,你可以任意指定字符之间的大小关系(即重定义字典序),求有多少个串可能成为字典序最小的串,并输出它们

输入描述:

第一行一个数表示n
之后n行每行一个字符串表示给定的字符串

输出描述:

第一行输出一个数x表示可行的字符串个数
之后输出x行,每行输出一个可行的字符串
输出的顺序和输入的顺序一致
示例1

输入

6
mcfx
ak
ioi
wen
l
a

输出

5
mcfx
ioi
wen
l
a

备注:

对于100%的数据,
n <= 30000 , 字符串总长<= 300000
字符集为小写字符
题目很是扯淡,,数据更扯淡,,不知道字符最大长度,MLE了几次,改小了又WA,还好最后试对了= =要是给出字符串最大长度就好了。
比赛时根本不知道题目在说什么鬼,其实就是询问某个字符串是否能最小,考虑作为最小的条件,S(最小)与另个字符串P比较时,遇到的第一个不相等的字符(位置j)时,S[j]<P[j]要成立,
我们将所有的字符串建成一颗trie时,对于某个被当做最小的字母,经过的所有的节点都要小于它的兄弟节点。暴力的找一下每个节点的兄弟建图即可。e[i][j]=1表示字符i<j成立。
我们只要找到所有的这些条件,在讨论是否能同时满足即可,这个问题显然就是拓扑排序,只要不出现环即可,问题转化为找图中是否有环。用floyd传递闭包即可。这个题有点卡时空。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAX_SIG=26;
 4 const int MAX_NOD=250000;
 5 char str[30005][25];
 6 bool ok[30005];
 7 int ch[MAX_NOD][MAX_SIG];
 8 int val[MAX_NOD],sz;
 9 char s[MAX_NOD];
10 int e[30][30];
11 int idx(char c){return c-'a';}
12 
13 void _insert(char *s)
14 {
15     int u=0,n=strlen(s);
16     for(int i=0;i<n;++i){
17         int c=idx(s[i]);
18         if(!ch[u][c]) ch[u][c]=sz++;
19         u=ch[u][c];
20     }
21     val[u]++;
22 }
23 
24 bool solve(int k)
25 {
26   memset(e,0,sizeof(e));
27   int n=strlen(str[k]);
28   int u=0;
29   for(int i=0;i<n;++i){
30     int c=idx(str[k][i]);
31     if(val[ch[u][c]]&&i!=n-1) return 0;
32     for(int j=0;j<MAX_SIG;++j){
33         if(j==c) continue;
34         if(ch[u][j]) e[c][j]=1;
35     }
36     u=ch[u][c];
37   }
38   for(int k=0;k<MAX_SIG;++k)
39   {
40       for(int i=0;i<MAX_SIG;++i)
41       {
42           if(!e[i][k]) continue;
43           for(int j=0;j<MAX_SIG;++j)
44           {
45             if(e[k][j]&&e[j][i]) return 0;
46           }
47       }
48       for(int i=0;i<MAX_SIG;++i)
49       {
50           if(!e[i][k]) continue;
51           for(int j=0;j<MAX_SIG;++j)
52           {
53               if(e[k][j]) e[i][j]=1;
54           }
55       }
56   }
57     return 1;
58 }
59 
60 int main()
61 {
62     int n;
63     while(cin>>n){
64         sz=1;
65         for(int i=1;i<=n;++i){
66             scanf("%s",str[i]);
67             _insert(str[i]);
68         }
69         int ans=0;
70         for(int i=1;i<=n;++i){
71             int k=solve(i);
72             if(k){
73                 ok[i]=1;
74                 ans++;
75             }
76         }
77         cout<<ans<<endl;
78         for(int i=1;i<=n;++i)
79             if(ok[i]) cout<<str[i]<<endl;
80     }
81     return 0;
82 }

 

posted @ 2018-02-01 19:57  *zzq  阅读(493)  评论(0编辑  收藏  举报