BZOJ3012 First!题解(Trie树+拓扑排序)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/85951329

题目:BZOJ3012.
题目大意:给定一些字符串,求在每一个串是否能在一个字典顺序下字典序最小.

这道题一看到要拓扑排序就懵了,想了一下如何建图也没有想出来,这种建图的套路题做的少啊…

首先我们先确定一个性质,就是当一个串有一个前缀串也在给定串中时,这个串肯定不可能字典序最小了.

于是我们就发现这道题要查一个串是否有前缀也在给定串中,就可以很自然的想到Trie树.

想到Trie树后,我们考虑一个串字典序最小时,优先让前面的最小,也就是说我们可以从Trie的根开始往下,与当前节点相连的每一层边中,字典序最小的串所对应的边必须是最小的.

这时我们就想到,可以建一张图以每个字符作为一个节点,当一个字符x必须大于另一个字符y时就连一条从x到y的有向边,那是否矛盾的问题就变成了判环问题,于是我们就可以愉快的写拓扑排序判环了.时间复杂度   O ( 26 m + 2 6 2 n ) \ O(26m+26^2n) .

所以代码如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;
#define m(a) memset(a,0,sizeof(a))

const int N=30000,M=300000,C=26;

struct Trie{
  int s[C],cnt;
  Trie(){m(s);cnt=0;} 
}tr[M+9];
int cn;

void Build(){tr[cn=1]=Trie();}

void Insert(char *c,int len){
  int x=1;
  for (int i=1;i<=len;++i)
    if (tr[x].s[c[i]-'a']) x=tr[x].s[c[i]-'a'];
    else {
      tr[x].s[c[i]-'a']=++cn;
      tr[cn]=Trie();
      x=cn;
    }
  ++tr[x].cnt;
}

int e[C+9][C+9],deg[C+9];
queue<int>q;

bool topsort(){
  for (int i=0;i<C;++i)
    if (!deg[i]) q.push(i);
  int t;
  while (!q.empty()){
  	t=q.front();q.pop();
  	for (int i=0;i<C;++i)
  	  if (e[t][i]){
  	  	deg[i]-=e[t][i];
  	  	if (!deg[i]) q.push(i);
  	  }
  }
  for (int i=0;i<C;++i)
    if (deg[i]) return false;
  return true;
}

bool Check(char *c,int len){
  int x=1;
  for (int i=0;i<C;++i){
    for (int j=0;j<C;++j)
      e[i][j]=0;
    deg[i]=0;
  }
  for (int i=1;i<=len;++i)
    if (tr[x].s[c[i]-'a']){
      if (tr[x].cnt) return false;
      for (int j=0;j<C;++j)
        if (c[i]-'a'^j&&tr[x].s[j]) ++e[c[i]-'a'][j],++deg[j];
      x=tr[x].s[c[i]-'a'];
    }else break;
  return topsort();
}

vector<char> c[N+9],ans[N+9];
char tmp[M+9];
int len[N+9],n,m;
int la[N+9],k;

Abigail into(){
  scanf("%d",&n);
  Build();
  for (int i=1;i<=n;++i){
  	scanf("%s",tmp+1);
  	len[i]=strlen(tmp+1);
  	Insert(tmp,len[i]);
  	c[i].push_back(0);
  	for (int j=1;j<=len[i];++j)
  	  c[i].push_back(tmp[j]);
  }
}

Abigail work(){
  for (int i=1;i<=n;++i){
  	for (int j=1;j<=len[i];++j)
  	  tmp[j]=c[i][j];
  	if (!Check(tmp,len[i])) continue;
  	la[++k]=len[i];
  	ans[k].push_back(0);
  	for (int j=1;j<=len[i];++j)
  	  ans[k].push_back(tmp[j]);
  }
}

Abigail outo(){
  printf("%d\n",k);
  for (int i=1;i<=k;++i){
  	for (int j=1;j<=la[i];++j)
  	  putchar(ans[i][j]);
	puts("");
  }
}

int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/85951329
今日推荐