一、实验目的

1.熟练掌握DFA与NFA的定义与有关概念。
2.理解并掌握确定的有穷自动机的最小化等算法。

二、实验要求

输入:DFA
输出:最小化的DFA

三、实验过程

1.化简DFA关键在于把它的状态集分成一些两两互不相交的子集,使得任何两个不相交的子集间的状态都是可区分的,而同一个子集中的任何两个状态都是等价的,这样可以以一个状态作为代表而删去其他等价的状态,然后将无关状态删去,也就获得了状态数最小的DFA。

2.DFA的化简算法:

(1)首先将DFAM的状态划分出终止状态集K1和非终止状态集K2。K=K1∪K2,

由上述定义知,K1和K2是不等价的。

(2)对各状态集每次按下面的方法进一步划分,直到不再产生新的划分。设第i次划分已将状态集划分为k组,即:

用python实现DFA最小化 dfa最小化的步骤_用python实现DFA最小化

用python实现DFA最小化 dfa最小化的步骤_c++_02

用python实现DFA最小化 dfa最小化的步骤_数据结构_03

(3)重复第〔2〕步,直到每一个集合不能再划分为止,此时每个状态集合
中的状态均是等价的。
(4)合并等价状态,即在等价状态集中取任意一个状态作为代表,删去其他—切等价状态。
(5)假如有无关状态,如此将其删去。根据以上方法就将确定有限自动机进展了简化,而且简化后的自动机是原自动机的状态最少的自动机。

四、实验结果

用python实现DFA最小化 dfa最小化的步骤_i++_04

五、代码实现

#include<iostream> 
#include<string>
using namespace std; 
#define max 100 
struct edge{ 
	string first;//边的初始结点 
	string change;//边的条件 
	string last;//边的终点
 }; 
int N;//NFA 的边数 
string part[max];//分割子集 

//状态集合 I 的 a 弧转换 
string move(string jihe,char ch,edge *b)
{
	int i,j; 
  	string s=""; 
 	for(i=0;i<jihe.length();i++)
	{
		for(j=0;j<N;j++)
		{ 
			if(b[j].first[0]==jihe[i]&&b[j].change[0]==ch)
 				s=s+b[j].last;
 		} 
	}
	if(s=="")return "&"; 
	else return s;
 }

//判断子串是否存在在某一集合
bool isexist(string s,string d) { 
	if(d!=""&&0<=d.find(s)&&d.find(s)<=d.length()-1)return 1; 
    else return 0;
 }

//分割子集法进行 DFA 的最小化 
int divide(edge *b,string change) {
	int x,m,flag=2,flag0,i,j; 
	string ss,part0[max]; 
	flag0=flag; 
	for(x=0;x<change.length();x++) { 
		for(m=0;m<flag0;m++)
{
			for(i=0;i<part[m].length();i++) {
				ss=move(part[m].substr(i,1),change[x],b);
				for(j=0;j<flag;j++) { 
					if(isexist(ss,part[j]))part0[j]=part0[j]+part[m].substr(i,1); if(ss=="&") {
						part0[flag]=part0[flag]+part[m].substr(i,1); 
						break;
					 } 
				}
			 }
			for(j=0;j<=flag;j++) {
				if(part0[j]!=""&&part0[j]!=part[m]) { 
					part[flag++]=part0[j]; 
					part0[j]="";
					part[m]="";
				 }
				else part0[j]="";
			 }
		 }
		flag0=flag;
	 }
	return flag;
 }

int main()
{
	int i,j,flag,x;
	string Change;//输入符号
	string ss;
	edge *b=new edge[max];
	cout<<"-------请输入DFA各边信息:(空用&表示)--------"<<endl<<endl
	<<"-----------------以输入$结束----------------"<<endl;
	for(i=0;i<max;i++)
	{
	cin>>b[i].first;
	if(b[i].first=="$")break;
	else
		cin>>b[i].change>>b[i].last;		
	}
	N=i;
	cout<<"请输入该DFA的终态集合: "<<endl;
	cin>>part[1];
	cout<<"请输入该DFA的非终态集合: "<<endl;
	cin>>part[0];
	cout<<"请输入此DFA状态中的输入符号即边上的条件:"<<endl;
	cin>>Change;
	flag=divide(b,Change);
	cout<<"此DFA最小化划分的子集如下: "<<endl;
	for(i=0;i<flag;i++)
	{
		if(part[i]!="")cout<<part[i]<<endl;
	}
	cout<<"用状态A,B,C…等代替子集:";
	for(i=0;i<flag;i++)
	{
		if(part[i]!="")cout<<" i"<<part[i]<<"},";
	}
	cout<<endl<<"则DFA最小化后的各边信息如下: "<<endl;
	char letters[max];
	char letter='A';
	for(i=0;i<flag;i++)
	{
		if(part[i]!="")
		{
			letters[i]=letter;
			++letter;
		}	
	}
	for(i=0;i<flag;i++)
		for(j=0;j<Change.length();j++)
		{
			ss=move(part[i],Change[j],b);
			if(part[i]!=""&&ss!="&")cout<<letters[i]<<" "<<Change[j]<<" ";
			for(x=0;x<flag;x++)
				if(isexist(ss.substr(0, 1),part[x]))cout<<letters[x]<<endl;
		}
	system("pause");
}