忘记拉窗帘

深刻发现带手机回去的坏处,快睡着了基友回了QQ,然后聊着聊着聊到了两点。

于是想睡个好觉就没带手机回,然后忘记拉窗帘T.T,一大早就醒了。

不带手机回去的话只能想想题了,也挺好的,不蛋疼。

果然想清楚了写就1A了,特此记录。

最近空了就会做做题玩,明年要找工作了,总是玩多塔炉石的话,可能会失业的吧。切切水题也是有乐趣的。然而却没有毁灭的快感。不多想了。

 

题目是hihocoder题库的#1036,多目标匹配

6
aaabc
aaac
abcc
ac
bcd
cd
aaaaaaaaaaabaaadaaac

YES

5
aaabc
aaac
abcc
bcd
cd
aaaaaaaaaaabaaadaac

NO

 

他那个提示还是很不错的,很不清楚,给做题的人留了很多想象空间(挖槽,黑人水平可以啊)。

我凭着印象利用KMP的思想搞了个类似自动机的东西。

 

KMP hihocoder里面也有,贴一个代码

#include<iostream>
#include<vector>
#include<string>

using namespace std;

class KMP
{
public:
    KMP(const string&);
    int match(const string&);
private:
    string pattern;
    vector<int> next;
};

int main()
{
    int N;
    cin >> N;
    while (N--)
    {
        string pattern;
        string s;
        cin >> pattern;
        cin >> s;
        KMP tmp = KMP(pattern);
        int answer = tmp.match(s);
        cout << answer << endl;
    }
    return 0;
}

KMP::KMP(const string& p0)
{
    pattern = p0;
    next = vector<int>(p0.size()+1,0);
    next[0] = next[1] = 0;
    for (int i = 1; i < p0.size(); i++)
    {
        int ans = next[i];
        while (ans && p0[ans] != p0[i]) ans = next[ans];
        if (p0[ans] == p0[i]) ans++;
        next[i+1] = ans;
    }
}

int KMP::match(const string& s)
{
    int ret = 0;
    int c = 0;
    for (int i = 0; i < s.size(); i++)
    {
        while (c && s[i] != pattern[c]) c = next[c];
        if (pattern[c] == s[i]) c++;
        if (c == pattern.size())
        {
            ret++;
            c = next[c];
        }
    }
    return ret;
}

next数组的定义:

next[i]表示s长度为i的前缀s[0..i-1]的一个最长的是s的前缀的真后缀。

next[i] = max{k|k<i,s[i-1-k+1..i-1] = s[0..k-1]}

每次匹配没命中就换到下一个可能匹配的位置

 

对于多目标匹配的话,需要先把所有的目标串建成Trie树,然后对于每个节点,到达这个状态以后,给出下一个字母之后的转移情况。

需要引入一个后缀指针,我把它定义成,当前路径上的字符串最长的在Trie树里面的真后缀。

根节点,和根节点儿子的后缀指针就是根节点。利用bfs求出后缀指针和转移的指针。

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>
#include<vector>
#include<string>
#include<fstream>

using namespace std;

class Trie
{
public:
    Trie()
    {
        for (int i = 0; i < 26; i++)a[i] = nullptr;
        back = nullptr;
        f = false;
    }
    void ins(string&);
    void calc();
    bool match(const string&);
private:
    bool f;
    Trie* back;
    Trie* a[26];
};

int main()
{

    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);

    Trie* root = new Trie();
    int N;

    //ifstream fin{"in.txt"};

    cin >> N;
    while (N--)
    {
        string s;
        cin >> s;
        root->ins(s);
    }
    root->calc();
    string s;
    cin >> s;
    cout << (root->match(s) ? "YES" : "NO") << endl;

    return 0;
}

void Trie::ins(string& s)
{
    int len = s.length();
    Trie* p = this;
    for (int i = 0; i < len; i++)
    {
        int index = s[i] - 'a';
        if (!p->a[index])
        {
            Trie* tmp = new Trie();
            p->a[index] = tmp;
            p = tmp;
        }
        else
        {
            p = p->a[index];
        }
        if (i == len - 1) p->f = true;
    }
}

bool Trie::match(const string& s)
{
    int len = s.length();
    Trie* p = this;
    for (int i = 0; i < len; i++)
    {
        int index = s[i] - 'a';
        p = p->a[index];
        if (p->f) return true;
    }
    return false; 
}

void Trie::calc()
{
    Trie* p = this;
    p->back = p;
    for (int i = 0; i < 26;i++)
    if (p->a[i]) (p->a[i])->back = p;
    
    
    vector<Trie*> bfs;
    bfs.clear();
    bfs.push_back(p);
    int S = 0;
    int T = 0;
    while (S <= T)
    {
        Trie* p = bfs[S];
        for (int i = 0; i < 26;i++)
        if (p->a[i])
        {
            Trie* q = p->a[i];
            bfs.push_back(q);
            T++;
            if (p == this)
                q->back = p;
            else
                q->back = p->back->a[i];
        }
        else
        {
            if (p == this) p->a[i] = p;
            else p->a[i] = (p->back)->a[i];
        }
        S++;
    }
    
}

慢慢恢复吧。。好菜啊,,

你可能感兴趣的:(忘记拉窗帘)