树型DFS 字典树

给定若干字符串,输出两两strcmp比较的时候每一次比较了多少次

UVA 11732
题目链接https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2832

说实话...这个想起来就头疼

我们知道strcmp实际上是从头比较到尾,也就是说实际上比较一次on也就可以了..但是这个输入会有23兆

然后我们就可以思考,实际上strcmp的比较就是a[i]和b[i]相比,必然是对应位置上面的比较.回想一下trie的构建过程,实际上对于一棵字典树,当且仅当有一个位置不同的时候我们才会将其进行一个分叉,总共的比较次数实际上也就是访问路上走过的路

所以就想到了对于所有的字符串构建这样的一棵字典树,然后进行一次dfs,递归到叶子节点之后,再返回父亲节点,将情况返回回去.

因为我们已经选定过一边之后我们仍要获得另一边的关系,这个获取是盲目的,所以在获取之后我们又要将结果除2

差不多了

#include
#include
#include
#include
#include


using namespace std;
const int maxnode = 4e6 + 7;
const int sigma_size = 26;


struct Trie{
    int head[maxnode];//head[i]即i节点的左儿子是什么
    int next[maxnode];//next[i]保存了它的右边的兄弟.
    char ch[maxnode];
    int tot[maxnode];tot[i]表示i节点的大小
    int sz;
    long long ans;
    void clear() {
        sz = 1;
        tot[0] = head[0] = next[0] = 0;
    }

    void insert(const char *s){
        int u = 0, v, n = strlen(s);
        tot[0] ++;
        for (int i = 0;i <= n;i ++){
            bool found = false;
            for (v = head[u]; v; v = next[v]){
                if (ch[v] == s[i]){
                    found = true;
                    break;
                }
            }
            if (!found){
                v = sz ++;
                tot[v] = 0;
                ch[v] = s[i];
                next[v] = head[u];
                head[u] = v;
                head[v] = 0;
            }
            u = v;
            tot[u] ++;
        }
    }

    void dfs(int depth, int u){
        if (head[u] == 0){
            ans += tot[u] * (tot[u] - 1) * depth;//递归到叶子,访问父亲是否有分叉,有分叉就纳入答案
        }
        else{
            int sum = 0;
            for (int v = head[u]; v; v = next[v]){
                sum += tot[v] *(tot[u] - tot[v]);//作为父亲节点,选取一边的答案,那么实际上另一边的答案可以直接相乘
            }
            ans += sum / 2 * (2 * depth + 1);//但是由于这样的选择是盲目的,所以我们需要将其除2
            for (int v = head[u]; v ; v = next[v]){
                dfs(depth + 1, v);
            }
        }
    }

    long long count(){
        ans = 0;
        dfs(0, 0);
        return ans;
    }
};

const int maxl = 1010;

int n;
char word[maxl];
Trie trie;


int main(){
    int kase = 1;
    while (~scanf("%d", &n), n ){
        trie.clear();
        for (int i = 0;i < n;i ++){
            scanf("%s", word );
            trie.insert(word);
        }
        printf("Case %d: %lld\n", kase ++, trie.count());
    }
    return 0;
}

你可能感兴趣的:(树型DFS 字典树)