忘记拉窗帘
深刻发现带手机回去的坏处,快睡着了基友回了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++; } }
慢慢恢复吧。。好菜啊,,