CodeForces 566 A Matching Names(Trie 匹配LCP和最大)

来源:互联网 发布:mac可以玩lucky dog1 编辑:程序博客网 时间:2024/06/07 06:09

题意:有n个A字符串和n个B字符串,问如何匹配能使LCP(最长公共前缀)和最大。


思路:将A和B分别插入Trie,节点保存的是具有该前缀的字符串id,然后对Trie进行dfs,优先选择深的匹配,并标记。 然后回溯去

匹配,被标记过的不再进行匹配。


代码:

#include<bits/stdc++.h>using namespace std;const int maxnode = 8e5+5;int ch[maxnode][26], sz;char str[maxnode];bool vis[maxnode][2];int match[maxnode];vector<int> val[maxnode][2];void init(){    sz = 1;    memset(ch[0], 0, sizeof(ch[0]));}void Insert(char *s, int id, int v){    int u = 0;    int len = strlen(s);    val[u][id].push_back(v);    //最后几个可能一个字符都不匹配,所以一定要在根处也加上    for(int i = 0; i < len; i++)    {        if(ch[u][s[i]-'a'] == 0)        {            memset(ch[sz], 0, sizeof(ch[sz]));            val[sz][id].clear();            ch[u][s[i]-'a'] = sz++;        }        u = ch[u][s[i]-'a'];        val[u][id].push_back(v);    }}int dfs(int dep, int u){    int ans = 0;    for(int i = 0; i < 26; i++)        if(ch[u][i])    //尽可能深            ans += dfs(dep+1, ch[u][i]);    vector<int> tmp[2];    for(int i = 0; i < 2; i++)        for(int j = 0; j < val[u][i].size(); j++)            if(!vis[val[u][i][j]][i])   //到这一层还没匹配过的具有公共前缀的都可以进行匹配了 已经是最优了                tmp[i].push_back(val[u][i][j]);    int num = min(tmp[0].size(), tmp[1].size());    //能匹配的对数    ans += dep*num;    for(int i = 0; i < num; i++)    {        match[tmp[0][i]] = tmp[1][i];        vis[tmp[0][i]][0] = vis[tmp[1][i]][1] = 1;  //匹配并标记用过    }    return ans;}int main(void){    int n;    while(cin >> n)    {        init();        memset(vis, 0, sizeof(vis));        for(int i = 1; i <= n; i++)            scanf(" %s", str), Insert(str, 0, i);        for(int i = 1; i <= n; i++)            scanf(" %s", str), Insert(str, 1, i);        printf("%d\n", dfs(0, 0));        for(int i = 1; i <= n; i++)            printf("%d %d\n", i, match[i]);    }    return 0;}