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 }

原文地址:https://www.cnblogs.com/suika/p/8435786.html

时间: 2024-07-30 02:46:32

BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序的相关文章

bzoj 3832: [Poi2014]Rally(线段树+拓扑排序)

3832: [Poi2014]Rally Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge Submit: 113  Solved: 56 [Submit][Status][Discuss] Description An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long distance cyclis

Codeforces Round #363 Fix a Tree(树 拓扑排序)

先做拓扑排序,再bfs处理 #include<cstdio>#include<iostream>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<map>#include<stack>#include<queue>#include<vector>#include<cmath&g

HDU5638 / BestCoder Round #74 (div.1) 1003 Toposort 线段树+拓扑排序

Toposort 问题描述 给出nn个点mm条边的有向无环图. 要求删掉恰好kk条边使得字典序最小的拓扑序列尽可能小. 输入描述 输入包含多组数据. 第一行有一个整数TT, 表示测试数据组数. 对于每组数据: 第一行包含3个整数nn, mm和kk (1 \le n \le 100000, 0 \le k \le m \le 200000)(1≤n≤100000,0≤k≤m≤200000), 表示图中结点数目, 图中边的数目以及要删的边数. 接下来mm行, 每行包含两个整数u_iu?i?? and

hdu 5195 DZY Loves Topological Sorting 线段树+拓扑排序

DZY Loves Topological Sorting Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5195 Description A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for ev

hdu5195 DZY Loves Topological Sorting 线段树+拓扑排序

要求在一个DAG中删去不多于k条边,使得拓扑序的字典序最大. 贪心策略:每次删去入度小于res的,序号尽量大的点的入边. 需要用线段树维护区间最小值. 代码: #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<vector> using name

[CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)

题目描述 你有一个长度为$n$的排列$P$与一个正整数$K$你可以进行如下操作若干次使得排列的字典序尽量小对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j$,交换$P_i$与$P_j$ 输入格式 第一行包括两个正整数$n$与$K$第二行包括$n$个正整数,第$i$个正整数表示$P_i$ 输出格式 输出一个新排列表示答案输出共$n$行,第$i$行表示$P_i$ 样例 样例输入: 8 34 5 7 8 3 1 2 6 样例输出: 12675348 数据范

HDU 5195 DZY Loves Topological Sorting (拓扑排序+线段树)

题目地址:HDU 5195 简直受不了了..BC第二题都开始线段树+拓扑排序了... 这题很容易想到拓扑排序过程中贪心,但是贪心容易TLE,所以需要用数据结构去维护,我用的是线段树维护.每次找入度小于等于k的编号最大的点,这样就可以保证字典序一定是最大的. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorith

【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】

目录: 1.A[树相关]    2.B[找规律]    3.C[贪心][拓扑排序] A. 描述(A 输入文件 : A.input 输出文件 : A.output)一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大.输入描述第一行一个数n 表示这个城市一共有 n 个节点.接下来 n-1 行,每行两个数ai 和bi (1 ≤ ai,bi ≤ n ),分别表示从ai 到bi,有一条边,每条边的

hdu 5195 DZY Loves Topological Sorting BestCoder Round #35 1002 [ 拓扑排序 + 优先队列 || 线段树 ]

传送门 DZY Loves Topological Sorting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 221    Accepted Submission(s): 52 Problem Description A topological sort or topological ordering of a directed