1. 程式人生 > 其它 >GDUT-21級排位賽第一場 - F. A Poet Computer(字典樹)

GDUT-21級排位賽第一場 - F. A Poet Computer(字典樹)

題意

The ACM team is working on an AI project called (Eih Eye Three) that allows computers to write poems. One of the problems they stumbled upon is finding words with the same suffix. The ACM team constructed a dictionary of words, They are interested only in the longest common suffix, That is, a suffix common to three or more words in the dictionary… A suffix is any substring that starts from some arbitrary position in the string and reaches the end of the string. As the ACM team was also preparing for the ACM-TCPC2015 contest, they figured that the contestants can help in solving this problem. Your task is to write a program that finds a longest common suffix in a dictionary of words. An entry in the dictionary is a word of English letters only. Small letters are the same as capital letters. You can assume that there is exactly one unique solution for every test case.

輸入格式

The first line of the input contains an integer T, the number of test cases. Each test case starts with a line containing one integer K, then K lines follow, each containing one string “Si” that represents an entry in the dictionary. 0 < T ≤ 50 |Si| ≤ 100 0 < K ≤ 1000

輸出格式

For each test case, print on the first line “Case c:” where ‘c’ is the test case number. On the second line you should print an integer denoting the length of the longest common suffix and another integer denoting how many words have the suffix appeared in.

樣例1

Input Output
2
4
cocochannel
chrisschannel
MBCchannel
controlpanel
5
superman
batman
ironman
chrissbrown
MyCrown
Case 1:
7 3
Case 2:
3 3

思路

字典樹模板題,題目要我們求最長common字尾的長度,以及擁有這個字尾的字串(要求至少3人相同的字尾才能算是common)。我們可以把每一個輸入的字串逆序插入字典樹,然後搜尋字典樹。

注意計數器是在迴圈裡面加一,因為我們要統計的是擁有該字尾的字串數量,而不是某一個單詞的數量。

程式碼

#include <bits/stdc++.h>
using namespace std;
const int N = 5 + 1e5;

int tr[N][26], cnt[N], idx;
int maxl, pl;

int id(char c) {
    if (c >= 'a' && c <= 'z') return c-'a';
    else return c-'A';
}

void insert(char * s) {
    int n = strlen(s+1);
    int u = 1;
    for (int i = n; i >= 1; i--) { // 逆序建字典樹
        int t = id(s[i]);
        if (!tr[u][t]) tr[u][t] = ++idx;
        u = tr[u][t];
        cnt[u]++; // 求字首字尾的話應該在迴圈內加一,而不是在迴圈外
    }
}

void dfs(int u, int l) {
    if (l > maxl && cnt[u] >= 3) {
        maxl = l;
        pl = cnt[u];
    } else if (l == maxl && cnt[u] >= 3) {
        pl = max(pl, cnt[u]);
    }
    for (int i = 0; i < 26; i++) {
        if (tr[u][i]) {
            // cout << tr[u][i] << endl;
            dfs(tr[u][i], l+1);
        }
    }
}

int main() {
    int t;
    scanf("%d", &t);
    int kase = 1;
    while (t--) {
        memset(tr, 0, sizeof tr);
        memset(cnt, 0, sizeof cnt);
        idx = 1; maxl = 0; pl = 0; // maxl:maxLength pl:amount of people
        int k; scanf("%d", &k);
        char s[105];
        for (int i = 1; i <= k; i++) {
            scanf("%s", s+1);
            insert(s);
        }
        dfs(1, 0); //
        if (maxl == 0) {
            printf("Case %d:\n", kase++);
            printf("0 %d\n", k);
        } else {
            printf("Case %d:\n", kase++);
            printf("%d %d\n", maxl, pl);
        }
    }
}