BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序

Posted fcwww

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序相关的知识,希望对你有一定的参考价值。

BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序

题意:

给定n个总长不超过m的互不相同的字符串,现在你可以任意指定字符之间的大小关系。问有多少个串可能成为字典
序最小的串,并输出这些串。n <= 30,000 , m <= 300,000
分析:
首先不考虑大小关系,如果一个串是另一个串的前缀,那么另一个串一定不能成为字典序最小的串,我们可以用trie树很好的解决。
考虑前缀相同的情况,这个串在前缀后的字符应该和含有相同前缀的串在前缀后的字符有明确的大小关系,根据这个大小关系连边,我们用拓扑排序判断是否矛盾。
以上都满足则可以成为字典序最小的串。
代码:
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <queue>
 5 using namespace std;
 6 #define N 30050
 7 struct A
 8 {
 9     int son[30],end;
10 }t[N*10];
11 int n,tot,head[30],to[N],nxt[N],c[30],cnt=1,ans[30010];
12 char s[30010][310];
13 void add(int u,int v)
14 {
15     to[++cnt]=v;
16     nxt[cnt]=head[u];
17     head[u]=cnt;
18     c[v]++;
19 }
20 void insert(int x)
21 {
22     int p=1;
23     int len=strlen(s[x]+1);
24     for(int i=1;i<=len;i++)
25     {
26         int id=s[x][i]-a+1;
27         if(!t[p].son[id])t[p].son[id]=++cnt;
28         p=t[p].son[id];
29     }
30     t[p].end=1;
31 }
32 bool search(int x)
33 {
34     int p=1;
35     int len=strlen(s[x]+1);
36     for(int i=1;i<=len;i++)
37     {
38         if(t[p].end)return 0;
39         int id=s[x][i]-a+1;
40         for(int j=1;j<=26;j++)
41         {
42             if(j!=id&&t[p].son[j])
43             {
44                 add(id,j);
45             }
46         }
47         p=t[p].son[id];
48     }
49     return 1;
50 }
51 bool topsort()
52 {
53     queue <int> q;
54     for(int i=1;i<=26;i++)if(c[i]==0)q.push(i);
55     while(!q.empty())
56     {
57         int x=q.front();q.pop();
58         for(int i=head[x];i;i=nxt[i])
59         {
60             c[to[i]]--;
61             if(c[to[i]]==0)q.push(to[i]);
62         }
63     }
64     for(int i=1;i<=26;i++)if(c[i])return 0;
65     return 1;
66 }
67 int main()
68 {
69     scanf("%d",&n);
70     for(int i=1;i<=n;i++)
71     {
72         scanf("%s",s[i]+1);
73         insert(i);
74     }
75     for(int i=1;i<=n;i++)
76     {
77         memset(head,0,sizeof(head));
78         memset(c,0,sizeof(c));cnt=0;
79         if(!search(i))continue;
80         if(!topsort())continue;
81         ans[++tot]=i;
82     }
83     printf("%d\n",tot);
84     for(int i=1;i<=tot;i++)
85     {
86         printf("%s\n",s[ans[i]]+1);
87     }
88 }

 

 

以上是关于BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ_1774_[Usaco2009 Dec]Toll 过路费_floyd

[bzoj1692][Usaco2007 Dec]队列变换_后缀数组_贪心

BZOJ_1717_[Usaco2006 Dec]Milk Patterns 产奶的模式_后缀数组

[bzoj5483][Usaco2018 Dec]Balance Beam_凸包_概率期望

[bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分

[bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式_后缀数组_二分答案