NFA转DFA

#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
*/
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值