zoukankan      html  css  js  c++  java
  • luogu P3065 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个字符串,问哪些串能在特定的字母顺序中字典序最小。

        -by luogu

    http://daniu.luogu.org/problem/show?pid=3065



    字典(trie)树,没什么好讲的;

    建字典树后,如何check单词?

    首先性质1:

      一个单词的前缀是单词的单词非法;

    --显然,无论如何规定字典序,空就是最高的;

    然后在字典树上i位置选j字母——意味着我们认为j字母比i的其他子节点小,假设k字母正是这样一个子节点;

    这样的话,继续走下去时,如果在某个节点时,我们想走k字母但是发现j字母也是这个节点的儿子,那我们就走不了k了;

    然后这个单词非法;

    可以考虑用拓扑排序的思想规定大小;

    (如果可以走j,则其它子节点字母向j连有向边构成图,然后check就是从一个节点dfs,若遍历到一个点,他也是当前父节点的一个儿子,则单词非法,先check再建边);

    我一开始觉得这个方法效率玄学;

    然而其实图中无环所以dfs是单次O(26)的,于是,总效率是O(num*26)的(num总字符数)

    十分合适;

    代码如下:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 struct Trie{
     6     int ch[26];
     7     int flag,size;
     8 };
     9 Trie trie[300010];
    10 int n,tot;
    11 string word[300010];
    12 string word2[300010];
    13 int ans;
    14 int e[26][26];
    15 void Init();
    16 void bui_trie();
    17 void check(int );
    18 int dfs(int ,int );
    19 int main()
    20 {
    21     int i,j,k;
    22     Init();
    23     scanf("%d",&n);
    24     bui_trie();
    25     for(i=1;i<=n;i++){
    26         memset(e,0,sizeof(e));
    27         check(i);
    28     }
    29     printf("%d
    ",ans);
    30     for(i=1;i<=ans;i++)
    31         cout<<word2[i]<<'
    ';
    32 }
    33 void Init(){
    34     memset(trie,0,sizeof(trie));
    35     n=tot=ans=0;
    36 }
    37 void bui_trie(){
    38     int i,j,k;
    39     for(i=1;i<=n;i++){
    40         cin>>word[i];k=0;
    41         for(j=0;j<word[i].size();j++){
    42             if(!trie[k].ch[word[i][j]-'a'])
    43                 trie[k].ch[word[i][j]-'a']=++tot;
    44             k=trie[k].ch[word[i][j]-'a'];
    45         }
    46         trie[k].flag=1;
    47     }
    48 }
    49 void check(int x){
    50     int i,j,k=0,l;
    51     for(i=0;i<word[x].size();i++){
    52         if(trie[k].flag)return;
    53         j=trie[k].ch[word[x][i]-'a'];
    54         if(dfs(word[x][i]-'a',k))
    55             return;
    56         for(l=0;l<=25;l++)
    57             if(trie[k].ch[l]&&l!=word[x][i]-'a')
    58                 e[l][++e[l][0]]=word[x][i]-'a';
    59         k=j;
    60     }
    61     word2[++ans]=word[x];
    62 }
    63 int dfs(int now,int k){
    64     int re=0,i;
    65     for(i=1;i<=e[now][0];i++)
    66         if(!trie[k].ch[e[now][i]]&&!re)
    67             re=dfs(e[now][i],k);
    68         else
    69             return 1;
    70         return re;
    71 }
  • 相关阅读:
    java 代码 添加控件 修改位置 View
    获取整个Activity的layout
    线程加锁 同步
    应用内悬浮按钮 可吸附 展开有动画 mini播放器
    svg 动画
    动画之二:属性动画 Property Animation
    ButterKnife 免去findviewby的麻烦
    ImageView 控件的宽高随图片变化
    python pip使用国内镜像安装第三方库:命令行或PyCharm
    pycharm安装pika提示CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com>
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/6735088.html
Copyright © 2011-2022 走看看