將非肯定性有限狀態自動機經過子集法構造肯定性有限狀態自動機。c++
1,讀入NFA狀態。注意最後須要設置終止狀態。ide
2,初始態取空,構造DFA的l0狀態,將l0加入未標記狀態隊列quespa
3,當que不爲空,取出一個狀態依次作轉移和取空操做,並構造出當前轉移狀態tmp。debug
4,如tmp是一個新狀態,加入到隊列中。c++11
5,將構造出的DFA用做模式識別。code
1,文件讀入NFA狀態轉換圖,採用vector存儲。blog
2,判斷狀態tmp是不是一個新的狀態使用自定義hash方法。隊列
3,取空操做因爲能夠轉移多步空字符,採用BFS實現。ip
4,源代碼編譯環境MinGW GCC 8.2.0,c++11,低於c++11的版本不兼容。ci
#include <bits/stdc++.h> using namespace std; using P = pair<int, char>; using ll = long long; const int maxn = 1e3 + 10; const int prime = 31; const ll mod = 1e9 + 7; int getHash(const set<int> &s) { ll res = 0; for (auto x : s) res = res * prime + x; return res % mod; } struct FA { int debug = 0; char ep = '*'; set<char> chs; int cnt = 0; //最大狀態數 vector<P> move[maxn]; set<int> end_state; void setDebug(int de) { debug = de; } void addState(int s, int t, char ch) { move[s].emplace_back(t, ch); if (ch != ep) chs.emplace(ch); cnt = max(cnt, max(s, t)); } void addEndState(int s) { end_state.emplace(s); } void init(string file) { ifstream in(file); int m; in >> m; //邊數 for (int i = 0; i < m; i++) { int s, t; char ch; in >> s >> t >> ch; addState(s, t, ch); } in >> m; //終止狀態數目 for (int i = 0; i < m; i++) { int st; in >> st; end_state.emplace(st); } if (debug) cout << "done.\n"; } set<int> bfs(set<int> s, char ch) { set<int> res; res.clear(); queue<int> q; while (!q.empty()) q.pop(); for (auto it : s) q.emplace(it); while (!q.empty()) { int now = q.front(); q.pop(); if (res.count(now)) continue; res.emplace(now); int sz = move[now].size(); for (int i = 0; i < sz; i++) { P tmp = move[now][i]; if (tmp.second == ch && !res.count(tmp.first)) q.emplace(tmp.first); } } return res; } FA getDFA() { FA res; set<int> st; map<int, set<int>> mp; unordered_map<int, int> mp2; mp2.clear(); mp.clear(); st.clear(); st.emplace(0); set<int> cur = bfs(st, ep); //初態計算,同時以後的st也表明了計算出來的狀態 mp[0] = cur; //初態hash值爲0不用計算 queue<int> q; st.clear(); q.emplace(0); mp2[0] = 0; int num = 1; //狀態數目 while (!q.empty()) { int cur = q.front(); q.pop(); if (st.count(cur)) continue; st.emplace(cur); set<int> now = mp[mp2[cur]]; for (auto ch : chs) { set<int> to; to.clear(); for (auto it : now) //轉移 { int sz = move[it].size(); for (int j = 0; j < sz; j++) { P tmp = move[it][j]; if (tmp.second == ch) to.emplace(tmp.first); } } to = bfs(to, ep); //取空 int ha = getHash(to); if (!st.count(ha)) { q.emplace(ha); mp2[ha] = num; mp[num++] = to; } if (debug) { cout << mp2[cur] << "->" << mp2[ha] << " " << ch << "\n"; for (auto x : mp[mp2[cur]]) cout << x << " "; cout << "\n"; for (auto x : mp[mp2[ha]]) cout << x << " "; cout << "\n"; } res.addState(mp2[cur], mp2[ha], ch); } } for (int x = 0; x < num; x++) { set<int> tmp = mp[x]; int f = 0; for (auto y : end_state) if (tmp.count(y)) { f = 1; break; } if (f) res.addEndState(x); } return res; } int isok(string to) { int len = to.size(); int st = 0; for (int i = 0; i < len; i++) { char ch = to[i]; int sz = move[st].size(); int f = 0; for (int j = 0; j < sz && !f; j++) { P tmp = move[st][j]; if (tmp.second == ch) { f = 1; st = tmp.first; } } if (!f) break; } return end_state.count(st); } void diplayEnd() { for (auto x : end_state) cout << x << " "; cout << "\n"; } } NFA, DFA; int main() { NFA.init("prj2_5.txt"); DFA = NFA.getDFA(); cout << "Please enter matching sequence:\n"; string to; while (cin >> to && to != "#") { cout << (DFA.isok(to) ? "OK" : "NO") << "\n"; } return 0; }