洛谷 P3065 [USACO12DEC]First! G(trie树+拓扑排序)

传送门
先建好trie树,然后考虑怎么搜索这个树来得到正确答案.
如果一个字符串能够成为重新规划后字典序最小的那一个,那它在每一层上面都要大于其他节点.所以我们只需要一层一层的往下搜索,然后把其他节点看做一个点,建一条u->v的边,u是当前字符串,v是其他节点.最后判断建出来的图有无环即可(拓扑排序完成).
还要注意的是如果这颗树里存在这个字符串的前缀串的话也是非法的.这种非法情况无法用拓扑序判断,可以外加一个trie树常见的ed数组来判断.
用惯了namespace之后代码看起来感觉还是比较舒服的:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 1e6+10;

inline int read(){
    
    
    int x = 0,f=1;char ch = getchar();
    while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

namespace Map{
    
    
    #define max_n 100
    int n=0,ct,in[max_n],nxt[max_n],head[max_n],to[max_n],vis[max_n];
    void init(){
    
    
        mem(in,0),mem(head,0);ct = 0;mem(vis,0);n=0;
    }
    void addedge(int x,int y){
    
    
        nxt[++ct] = head[x];head[x] = ct;to[ct] = y;
        in[y]++;
        if(!vis[x]) n++,vis[x] = 1;
        if(!vis[y]) n++,vis[y] = 1;
    }
    bool check(){
    
    
        vi que;
        fir(i,0,25) if(vis[i] && !in[i]) que.pb(i);
        int sum = 0;
        while(que.size()){
    
    
            int u = que.back();sum++;
            que.pop_back();
            for(int i=head[u];i;i=nxt[i]){
    
    
                int y = to[i];
                if(--in[y] == 0) que.pb(y);
            }
        }
        if(sum == n) return true;
        return false;
    }
}
namespace Trie{
    
    
    vector<string> ans;
    int trie[26][N],ed[N],tot=1,p;
    void ins(string s){
    
    
        p = 1;
        for(auto x:s){
    
    
            int ch = x-'a';
            if(!trie[ch][p]) trie[ch][p] = ++ tot;
            p = trie[ch][p];
        }
        ed[p] = 1;
    }
    int ask(string s){
    
    
        Map::init();
        p = 1;
        bool f = 0;
        for(auto x:s){
    
    
            int ch = x-'a';
            fir(i,0,25){
    
    
                if(i == ch) continue;
                if(trie[i][p])
                    Map::addedge(ch,i);
            }
            if(ed[p]){
    
    
                f = 1;
                break;
            }
            p = trie[ch][p];
        }
        if(ed[p] > 1) f = 1;
        if(f) return 0;
        if(Map::check()){
    
    
            ans.pb(s);
            return 1;
        }
        return 0;
    }
}
string str[N];
int main(){
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    fir(i,1,n) cin >> str[i],Trie::ins(str[i]);
    int ans = 0;
    fir(i,1,n){
    
    
        ans += Trie::ask(str[i]);
    }
    cout << ans << "\n";
    for(auto x:Trie::ans){
    
    
        cout << x << endl;
    }

    return 0;
}    

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/109681874
今日推荐