#include <bits/stdc++.h>
#define MK make_pair
#define FI first
#define SE second
using namespace std;
const int N=1e5+5; //结点的最大数目
const int node_num=1e2+5; //最大状态结点编号,结点范围[1,Node_Num)
const int dfa_num=1e2+5; //最大状态集合数目
struct node{
int to_num; //可达状态编号
char convert_char; //转换字符
};
vector<node>e[node_num]; //状态结点之间的映射
vector<node>D[dfa_num]; //存放构造的dfa集合之间的状态转换关系
int dfa_tot=0; //用于DFA集合从小到大编号,同时也表示最终DFA状态集合数量
map<set<int>,int>dfa_set_exist; //判断dfa集合是否存在
map<int,set<int>>dfa_set; //构造的dfa集合
int m; //输入的弧数量
int n; //输入的状态结点数目
set<char>alpha; //有穷字母表
set<int>start_state,end_state; //初态集合,终态集合
int S_num,Z_num; //初终态结点数目
int S[node_num],Z[node_num]; //初态结点、终态结点
void Input(){
printf("-----------------NFA转换为等价的DFA(子集法)-----------------\n");
printf("请输入NFA的状态结点数目n,状态结点请保持输入范围为[0,n):");scanf("%d",&n);
printf("请输入NFA的初态结点数目:");scanf("%d",&S_num);
printf("请输入NFA的%d个初态结点编号(空格隔开,回车结束):",S_num);
for(int i=0;i<S_num;++i) scanf("%d",&S[i]);
printf("请输入NFA的终态结点数目:");scanf("%d",&Z_num);
printf("请输入NFA的%d个终态结点编号(空格隔开,回车结束):",Z_num);
for(int i=0;i<Z_num;++i) scanf("%d",&Z[i]);
printf("请输入转换的弧数目(有向边数目):");scanf("%d",&m);
printf("请输入NFA的%d条弧状态,输入格式:状态起点 转换字符 状态终点(#表示ε字符)\n",m);
printf("如:1 a 2 表示 状态结点1 可通过 a弧 到达 状态结点2\n");
for(int i=0;i<m;++i){
printf("输入第%d条弧:",i+1);
char ch[2];
int u,v;scanf("%d%s%d",&u,ch,&v);
if(ch[0]!='#') alpha.emplace(ch[0]);
e[u].push_back({v,ch[0]});
}
}
set<int> e_closure(set<int>T){ //状态集合T的ε闭包
set<int>Ans;//用来存状态集合T的ε闭包
stack<int>st; //利用栈实现DFS搜索状态集合T所有可达状态
for(auto it=T.begin();it!=T.end();++it){//将状态集合T的ε闭包入栈
st.emplace(*it);
Ans.insert(*it);//状态集合T本身就是自己的ε闭包
}
while(!st.empty()){
int u=st.top();
st.pop();
int cnt=e[u].size();//u结点能到达的节点的数目
for(int i=0;i<cnt;++i){
int v=e[u][i].to_num;//u结点能到达的节点的编号
char ch=e[u][i].convert_char;
if(ch!='#') continue; //只搜索状态结点的ε弧
if(!Ans.count(v)){ //存在未搜索过的状态结点,加入Ans集合
Ans.insert(v);
st.emplace(v); //v结点加入栈中,搜索经过任意条ε弧可达的状态结点
}
}
}
return Ans;//状态集合T的ε闭包
}
set<int> Move(set<int>T,char a){ //状态集合T的a弧转换
set<int>Ans;
for(auto it=T.begin();it!=T.end();++it){
int u=*it;
int cnt=e[u].size();
for(int i=0;i<cnt;++i){
int v=e[u][i].to_num;
char ch=e[u][i].convert_char;
if(ch!=a) continue; //只搜索经过一条a弧能够到达的状态结点
Ans.insert(v);
}
}
return Ans;//返回状态集合T的经过a弧转换得到的集合
}
void NfaToDfa(){
set<int>S0; //初始集合
for(int i=0;i<S_num;++i) S0.insert(S[i]);//把初始状态加入集合
S0=e_closure(S0);//求初始状态S0集合的ε-closure闭包
dfa_set.insert(MK(dfa_tot,S0));//将S0的ε-closure闭包用一个set保存,并且编号
dfa_set_exist[S0]=dfa_tot++;
queue<set<int>>q; //利用队列实现BFS遍历未被标记的子集
q.emplace(S0);//初始集合入队列
while(!q.empty()){ //存在未被标记的子集
set<int>T=q.front();
q.pop();
int num=dfa_set_exist[T];
for(auto it=alpha.begin();it!=alpha.end();++it){//遍历所有弧的字母表
set<int>newT=e_closure(Move(T,*it)); //计算ε-closure(move(T,a))
if(newT.size()==0) continue;
if(dfa_set_exist.find(newT)==dfa_set_exist.end()){ //判断集合是否未被标记
dfa_set_exist.insert(MK(newT,dfa_tot));
D[num].push_back({dfa_tot,*it}); //保存状态集合转换关系
dfa_set.insert(MK(dfa_tot++,newT));
q.emplace(newT);
}
else D[num].push_back({dfa_set_exist[newT],*it}); //保存状态集合转换关系
}
}
}
void getStartAndEndSet(){
for(int i=0;i<dfa_tot;++i){
set<int>now=dfa_set[i];
bool fg=0;
for(int j=0;j<S_num;++j){
if(now.count(S[j])){
start_state.emplace(i);
fg=1;
break;
}
}
if(fg) continue;
for(int j=0;j<Z_num;++j){
if(now.count(Z[j])){
end_state.emplace(i);
break;
}
}
}
}
void Output(){
printf("\n算法终止,构造了%d个子集\n",dfa_tot);
for(auto it=dfa_set.begin();it!=dfa_set.end();++it){
auto it2=it->SE.begin();
printf("T%d={%d",it->FI,*it2);
++it2;
for(;it2!=it->SE.end();++it2)printf(",%d",*it2);
printf("}\n");
}
printf("-----------NFA N 构造的DFA M 如下:-----------\n");
printf("S=[T0]");
for(int i=1;i<dfa_tot;++i) printf(",[T%d]",i);
printf("}\n");
auto alpha_it=alpha.begin();
printf("∑={%c",*alpha_it);
++alpha_it;
for(;alpha_it!=alpha.end();++alpha_it) printf(",%c",*alpha_it);
printf("}\n");
printf("状态转移关系如下:\n");
for(int i=0;i<dfa_tot;++i){
int cnt=D[i].size();
for(int j=0;j<cnt;++j) printf("D([T%d],%c)=[T%d]\n",i,D[i][j].convert_char,D[i][j].to_num);
}
printf("\n");
printf("S0=[T0");
auto it=start_state.begin();
++it;
for(;it!=start_state.end();++it) printf(",T%d",*it);
printf("]\n");
it=end_state.begin();
printf("St=[T%d",*it);
++it;
for(;it!=end_state.end();++it) printf(",T%d",*it);
printf("]\n");
}
int main(){
Input();//输入
NfaToDfa();//nfa确定化
getStartAndEndSet();//得到初态集和终态集
Output();//输出
return 0;
}
/*
11
1
0
1
10
13
0 # 1
1 # 2
1 # 4
2 a 3
4 b 5
3 # 6
5 # 6
6 # 1
6 # 7
0 # 7
7 a 8
8 b 9
9 b 10
*/
NFA转DFA
最新推荐文章于 2024-05-14 15:03:20 发布