实验内容
将非确定性有限状态自动机通过子集法构造确定性有限状态自动机。
实验步骤
1,读入NFA状态。注意最后需要设置终止状态。
2,初始态取空,构造DFA的l0状态,将l0加入未标记状态队列que
3,当que不为空,取出一个状态依次做转移和取空操作,并构造出当前转移状态tmp。
4,如tmp是一个新状态,加入到队列中。
5,将构造出的DFA用作模式识别。
具体实现
1,文件读入NFA状态转换图,采用vector存储。
2,判断状态tmp是否是一个新的状态使用自定义hash方法。
3,取空操作由于可以转移多步空字符,采用BFS实现。
4,源代码编译环境MinGW GCC 8.2.0,c++11,低于c++11的版本不兼容。
#include <bits/stdc++.h>
using namespace std;
using P = pair<int, char>;
using ll = long long;
const int maxn = 1e3 + ;
const int prime = ;
const ll mod = 1e9 + ;
int getHash(const set<int> &s)
{
ll res = ;
for (auto x : s)
res = res * prime + x;
return res % mod;
}
struct FA
{
int debug = ;
char ep = '*';
set<char> chs;
int cnt = ; //最大状态数
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 = ; i < m; i++)
{
int s, t;
char ch;
in >> s >> t >> ch;
addState(s, t, ch);
}
in >> m; //终止状态数目
for (int i = ; 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 = ; 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();
set<int> cur = bfs(st, ep); //初态计算,同时之后的st也代表了计算出来的状态
mp[] = cur; //初态hash值为0不用计算
queue<int> q;
st.clear();
q.emplace();
mp2[] = ;
int num = ; //状态数目
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 = ; 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 = ; x < num; x++)
{
set<int> tmp = mp[x];
int f = ;
for (auto y : end_state)
if (tmp.count(y))
{
f = ;
break;
}
if (f)
res.addEndState(x);
}
return res;
}
int isok(string to)
{
int len = to.size();
int st = ;
for (int i = ; i < len; i++)
{
char ch = to[i];
int sz = move[st].size();
int f = ;
for (int j = ; j < sz && !f; j++)
{
P tmp = move[st][j];
if (tmp.second == ch)
{
f = ;
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 ;
}