bzoj 3012: [Usaco2012 Dec]First! Trie+拓扑排序

题目大意:

给定n个总长不超过m的互不相同的字符串,现在你可以任意指定字符之间的大小关系。问有多少个串可能成为字典序最小的串,并输出这些串。n <= 30,000 , m <= 300,000

题解:

首先我们可以把所有的串插入到Trie树中。
然后我们枚举每个串,判断是否存在可行方案
我们枚举到一个串,那么我们就在Trie树中进行查找
每一次从某一个节点向下走的时候,我们都要保证当前走的这条支路是字典序最小的
也就是这条支路上的字母的字典序小于这个节点上的其他所有支路的字典序
所以我们就成功的找出了一些字典序的大小关系
所以我们只需要判断这个关系是不是存在环,如果存在环那么一定不可行
否则即可行
判环嘛。。。用拓扑排序不久好了嘛233.

然后让我来吐槽一下这个cin,cout会RE的题目
共30000个字符串,总长300000,是不是我要开一个30000*300000的char数组?
这内存不还得飞起来啊!!!!
用string不久好了? cin cout 不能用!!!你拿什么读入和输出啊!!!!
什么 cin cout 不能用???
可以用 ! 只是RE罢了!!!!
那怎么读入!!!??
你可以先读入一个char数组,然后转成string,然后输出的时候用putchar输出
。。。 。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 30010;
const int maxc = 300010;
int ch[maxc][27],nodecnt;
bool ed[maxc];
inline void insert(string s){
    int nw = 0,len = s.size();
    for(int i=0;i<len;++i){
        if(ch[nw][s[i]-'a'] == 0) ch[nw][s[i]-'a'] = ++nodecnt;
        nw = ch[nw][s[i]-'a'];
    }ed[nw] = true;
}
bool mp[40][40];int deg[40];
int q[40],l,r;
inline bool judge(string s){
    memset(mp,0,sizeof mp);
    memset(deg,0,sizeof deg);
    int nw = 0,len = s.size();
    for(int i=0;i<len;++i){
        for(int c='a';c<='z';++c){
            if((c == s[i]) || (ch[nw][c - 'a'] == 0)) continue;
            if(!mp[s[i]-'a'][c-'a']){
                mp[s[i]-'a'][c-'a'] = true;
                ++deg[c-'a'];
            }
        }
        if(ed[nw]) return false;
        nw = ch[nw][s[i]-'a'];
    }
    l = 0;r = -1;
    for(int i=0;i<26;++i){
        if(deg[i] == 0) q[++r] = i;
    }   
    while(l <= r){
        int u = q[l++];
        for(int i=0;i<26;++i){
            if(mp[u][i]){
                if(--deg[i] == 0) q[++r] = i;
            }
        }
    }
    if(r == 25) return true;
    return false;
}
bool flag[maxn];
string s[maxn];
char str[maxc];
int main(){
    int n;read(n);
    for(int i=1;i<=n;++i){
        scanf("%s",str);
        int m = strlen(str);s[i] = "";
        for(int j=0;j<m;++j){
            s[i] = s[i] + str[j];
        }insert(s[i]);
    }int ans = 0;
    for(int i=1;i<=n;++i){
        if(judge(s[i])){
            flag[i] = true;
            ++ ans;
        }
    }
    printf("%d\n",ans);
    for(int i=1;i<=n;++i){
        if(flag[i]){
            int m = s[i].size();
            for(int j=0;j<m;++j){
                putchar(s[i][j]);
            }puts("");
        }
    }
    getchar();getchar();
    return 0;
}
posted @ 2017-02-26 21:32  Sky_miner  阅读(311)  评论(0编辑  收藏  举报