BZOJ1212 [HNOI2004]L语言

看到最长前缀想到Trie字典树

但此题是分段匹配(多个单词),于是想到二重循环枚举起点

记录\(mark_i\)表示能否通过单词匹配到\(i\),如果可以则记录答案并以该点为起点继续匹配

若匹配过程中发现之前单词的结尾(可用结尾标记判断),则令当前\(mark=1\)

注:\(1MB\approx10^6\)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

bool bo[1000005];//1MB=1e6
int ch[1000005][30],n,m,tot = 1;
char str[1000005];
bool mark[1000005];//表示能通过多个单词匹配到i位置 
inline void write(int s)
{
    if(s < 0)
    {
        putchar('-');
        s = -s;
        write(s);
    }
    if(s > 9)
        write(s % 10);
    putchar(s % 10 + '0');
}
inline void Insert(char * s)//建Trie字典树 
{
    int u = 1,len = strlen(s + 1);
    for(int i = 1;i <= len; ++i)
    {
        int c = s[i] - 'a';
        if(!ch[u][c])
            ch[u][c] = ++tot;
        u = ch[u][c];
    }
    bo[u] = true;
}
inline void find(char * s)//匹配文章s 
{
    int ans,now = 1,len = strlen(s + 1);
    memset(mark,0,sizeof mark);
    mark[0] = 1;//0位置匹配根节点 
    for(int i = 0,k;i <= len; ++i)//从0开始! 
    {
        if(!mark[i])//不能匹配到当前位置 
            continue;
        else
            ans = i;//记录答案 
        for(k = i + 1,now = 1;k <= len; ++k)
        {
            int c = s[k] - 'a';
            now = ch[now][c];
            if(!now)
                break;
            if(bo[now])//发现单词结尾 
                mark[k] = 1;
        }
    }
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 1;i <= n; ++i)
    {
        cin >> str + 1;
        Insert(str);
    }
    for(int i = 1;i <= m; ++i)
    {
        cin >> str + 1;
        find(str);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pipa-peng/p/11901049.html