[代码向]DFA与NFA两道编程题
1.DFA识别语言
样例(仅供参考):
3 2
1 2
2 -1
-1 -1
2 -1
aa
b
bab
#
0 0
DFA特点:
(1)没有空串ε的转换
(2)对于任意状态s和输入符号a,只有一条标号为a的边离开s
因此只要构造好状态转换表,只要判断转化后的最终状态是否是接收状态就可以了.
代码如下:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int N=51,M=27;
int trans[N][M]; //状态转换表
int acc[N]; //终态集合
int cnt; //终态个数
bool isAc(int fin_st){
for(int i=0;i<cnt;i++){
if(fin_st == acc[i]) return true;
}
return false;
}
int main(){
//freopen("in.txt","r",stdin);
int n,m;
while(cin>>n>>m && (n && m)){
// 读
memset(trans,-1,sizeof(trans));
memset(acc,0,sizeof(acc));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>trans[i-1][j]; //按题意这里读入的是i-1
cnt=0;
while(cin>>acc[cnt++] && acc[cnt-1]!=-1){;}
cnt--;
string query;
while(cin>>query && query!="#"){
int start=0;
//状态转换
for(int i=0; i<query.length(); i++){
int next = trans[start][query[i]-'a'+1];
if(next==-1){ //提早剪枝
start=-1;
break;
}
else start=next;
}
//状态到终态则AC
if(isAc(start)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}
2.NFA识别语言
NFA特点:
(1)存在空串ε的转换,比如从状态a经过空串ε到达b,但b也可以经过ε转化,到达其他状态,所以需要求ε的闭包
(2)输入的不确定性,对于同一输入符号,可能到达不同的状态(包括空串)
处理思路和DFA类似,不过DFA输入输出得到的是一个状态,而在NFA中是一个状态集合。
先给出伪代码:
注意左边S和右边S不同,分别代表新旧状态。
数据如下:
4 3
{} {0,1} {0}
{} {} {2}
{} {} {3}
{} {} {}
3 -1
aaabb
abbab
abbaaabb
abbb
#
0 0
代码如下:
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
const int N=51,M=27;
vector<int> move_[N][M]; //状态转换表
int acc[N]; //终态集合
int cnt,n,m; //终态个数,n is states, m is alphabet num
bool flag[N]; //求闭包时状态是否重复
bool isAc(stack<int> &fn){
while(!fn.empty()){
for(int i=0;i<cnt;i++){
if(acc[i]==fn.top()) return true;
}
fn.pop();
}
return false;
}
void closure(stack<int> &ans,int n){ //求空串的闭包
vector<int> all_(move_[n][0]);
flag[n]=1;
ans.push(n);
for(int i=0;i<all_.size();i++){
if(!flag[move_[n][0][i]]) closure(ans,move_[n][0][i]);
}
}
int get_num(char* str,int &index){
int sum=0;
for(;(str[index]<='9')&&(str[index]>='0');index++){
sum=sum*10+str[index]-'0';
}
index--;
return sum;
}
int main(){
//freopen("in.txt","r",stdin);
char line[500];
char *ps;
char lash;
stack<int> oldState,newState;
while(scanf("%d %d%c",&n,&m,&lash) && (n && m)){
memset(move_,0,sizeof(move_));
memset(acc,0,sizeof(acc));
for(int i=0;i<n;i++){
gets(line);
int h=0;
ps=line;
for(int j=1;j<=m;j++){
for(;(line[h]!='}')&&(line[h]!='\0');h++){
if(line[h]<='9'&&line[h]>='0'){
int value=get_num(line,h);
move_[i][j-1].push_back(value);
}
}
h++; //再继续读下一个alpha
}
}
cnt=0;
while(cin>>acc[cnt++] && acc[cnt-1]!=-1){;}
cnt--;
string query;
while(cin>>query && query!="#"){
memset(flag,0,sizeof(flag));
closure(newState,0);
for(int i=0;i<query.length();i++){
while(!newState.empty()){ // each state move alpha
oldState.push(newState.top());
flag[newState.top()]=0; // retrieve the flag
newState.pop();
}
while(!oldState.empty()){
for(int k=0;k<move_[oldState.top()][query[i]-'a'+1].size();k++){
if(!flag[move_[oldState.top()][query[i]-'a'+1][k]]){
closure(newState,move_[oldState.top()][query[i]-'a'+1][k]);
}
}
oldState.pop();
}
}
if(isAc(newState)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}
本博客参考以下博主并诚恳致谢
1.https://blog.csdn.net/dalewzm/article/details/14521283