[bzoj3012][luogu3065][USACO12DEC][第一!First!] (trie+拓扑排序判环)

题目描述

Bessie has been playing with strings again. She found that by

changing the order of the alphabet she could make some strings come before all the others lexicographically (dictionary ordering).

For instance Bessie found that for the strings "omm", "moo", "mom", and "ommnom" she could make "mom" appear first using the standard alphabet and that she could make "omm" appear first using the alphabet

"abcdefghijklonmpqrstuvwxyz". However, Bessie couldn't figure out any way to make "moo" or "ommnom" appear first.

Help Bessie by computing which strings in the input could be

lexicographically first by rearranging the order of the alphabet. To compute if string X is lexicographically before string Y find the index of the first character in which they differ, j. If no such index exists then X is lexicographically before Y if X is shorter than Y. Otherwise X is lexicographically before Y if X[j] occurs earlier in the alphabet than Y[j].

给出n个字符串,问哪些串能在特定的字母顺序中字典序最小。

输入输出格式

输入格式:

 

  • Line 1: A single line containing N (1 <= N <= 30,000), the number of strings Bessie is playing with.

  • Lines 2..1+N: Each line contains a non-empty string. The total number of characters in all strings will be no more than 300,000. All characters in input will be lowercase characters 'a' through 'z'. Input will contain no duplicate strings.

 

输出格式:

 

  • Line 1: A single line containing K, the number of strings that could be lexicographically first.

  • Lines 2..1+K: The (1+i)th line should contain the ith string that could be lexicographically first. Strings should be output in the same order they were given in the input.

 

输入输出样例

输入样例#1:
4 
omm 
moo 
mom 
ommnom 
输出样例#1:
2 
omm 
mom 

说明

The example from the problem statement.

Only "omm" and "mom" can be ordered first.

Solution

要想使一个词语的字典序最小,首先应满足长度尽量短,也就是没有任何一个词构成当前词的前缀

其次是词的每一位都要严格大于与之享有共同前缀的词语

首先对词典建一棵trie

要满足答案的串必须满足其终止节点到根没有其他终止节点,也就是第一个限定

向需要规定大小关系的字符间连边

拓扑排序一下,判环,若无环则可以作为答案输出

(最近尽量写思路清晰但是比较长的程序,其实我是有能力写得很短跑得很快的,但在平时这样似乎没有什么意义,思路清晰最重要吧,毕竟把程序变快是很简单的事)

#include <stdio.h>
#include <memory.h>
#define MaxN 30010
#define MaxL 300010
#define MaxBuf 1<<22
#define Blue() ((S==T&&(T=(S=B)+fread(B,1,MaxBuf,stdin),S==T))?0:*S++)
char B[MaxBuf],*S=B,*T=B;
template<class Type>inline void Rin(Type &x){
    x=0;int c=Blue();
    for(;c<48||c>57;c=Blue())
        ;
    for(;c>47&&c<58;c=Blue())
        x=(x<<1)+(x<<3)+c-48;
}
inline void geTc(char *C,int &x){
    x=0;char c=Blue();
    for(;c<'a'||c>'z';c=Blue())
        ;
    for(;c>='a'&&c<='z';c=Blue())
        *C++=c,x++;
}
bool g[26][26];
char ch[MaxL],fol[MaxL];
int n,l,pointer,ans,lef[MaxN],in[26],out[26],o[MaxN];
class Trie{
    int ch[MaxL][26],root,tot,belong[MaxL];
public:
    Trie(){
        root=tot=1;
        memset(ch,0,sizeof ch);
        memset(belong,0,sizeof belong);
    }
    inline void insert(char *C,int len,int tim){
        int at=root;
        lef[tim]=pointer;
        for(int i=0;i<len;i++){
            fol[pointer++]=C[i];
            if(!ch[at][C[i]-'a'])
                ch[at][C[i]-'a']=++tot;
            at=ch[at][C[i]-'a'];
        }
        belong[at]=tim;
    }
    inline bool design(int i){
        int at=root;
        for(int j=lef[i];j<lef[i+1];j++){
            if(belong[at])return false;
            int c=fol[j]-'a';
            for(int k=0;k<26;k++)
                if(ch[at][k]&&k!=c&&!g[c][k]){
                    g[c][k]=true;
                    in[k]++;
                    out[c]++;
                }
            at=ch[at][c];
        }
        return true;
    }
}Tree;
namespace enumerate{
    bool vis[26];
    int _que[27],hd,tl,tot,sum;
    inline bool topsort(){
        tot=sum=0;
        hd=1;tl=0;
        for(int i=0;i<26;i++){
            if(in[i] || out[i])
                tot++;
            if(!in[i] && out[i]){
                _que[++tl]=i; vis[i]=true;
            }
            else vis[i]=false;
        }
        while(hd<=tl){
            sum++;
            int now=_que[hd++];
            for(int i=0;i<26;i++)
                if(g[now][i]){
                    in[i]--;
                    if(!in[i] && !vis[i]){
                        _que[++tl]=i; vis[i]=true;
                    }
                }
        }
        return tot==sum;
    }
    void main(){
        for(int i=1;i<=n;i++){
            memset(g,false,sizeof g);
            memset(in,0,sizeof in);
            memset(out,0,sizeof out);
            if(Tree.design(i) && topsort())
                o[++ans]=i;
        }
    }
}
#define FO(x) {freopen(#x".in","r",stdin);}
int main(){
    FO(usaco12dec first);
    Rin(n);
    for(int i=1;i<=n;i++){
        geTc(ch,l);
        Tree.insert(ch,l,i);
    }
    lef[n+1]=pointer;
    enumerate::main();
    printf("%d\n",ans);
    for(int i=1;i<=ans;i++){
        for(int j=lef[o[i]];j<lef[o[i]+1];j++)
            putchar(fol[j]);
        putchar('\n');
    }
    return 0;
}

 

posted @ 2017-01-28 15:45  keshuqi  阅读(395)  评论(0编辑  收藏  举报