soj-1001. NFA識別語言

N丶Z丨發表於2020-12-29

Description
對於給出的NFA和輸入的字串,判斷字串是否是NFA識別的語言。

Input
輸入有多組資料。每組資料的第一行是兩個整數N(N<=50)和M(M<=27),表示NFA有N個狀態,以及字母表有M-1個字元。NFA的N個狀態用整數0~N-1表示,狀態0為起始狀態。字母表包含小寫英文字母的前M-1個字元。接下來的N行,每行有M個整數集(用’{‘和’}'括起)。其中,第i行第1列的整數集表示在狀態i-1時,對應於є(空串)的狀態遷移;第i行第j(j>1)列的整數集,表示NFA在狀態i-1,當輸入符號為第j-1個小寫字母時,遷移到的狀態集。接下來的一行包含若干個整數,代表NFA的接受狀態,這一行以-1結尾。接下來的每一行是一個待識別的字串,字串的長度在1到50之間且只含有小寫字母。字串"#"代表本組資料結束。N=M=0表示輸入結束。

Output
對於每個待識別的字串,如果能被給出的NFA識別,輸出YES;否則輸出NO。

Sample Input

4 3
{} {0,1} {0}
{} {} {2}
{} {} {3}
{} {} {}
3 -1
aaabb
abbab
abbaaabb
abbb
#
0 0

Sample Output

YES
NO
YES
NO

Hint
輸入樣例是課本Figure 3.24的NFA。你需要實現的是課本Figure 3.33和3.37的演算法。

思路
模擬。
基本思路和DFA一樣,不過我們要考慮空狀態的轉移,以及我們需要存一個狀態集而不是一個狀態。

程式碼

#include<string>
#include<cstring>
#include<iostream>

using namespace std;
int n, m, accept_num;
char alphabet[27];
int accept[51];
int map[50][27][51];
int state[50];
int state1[50];
int statenum, state1num;
string s;
bool check;
void init(int n, int m){
	string s;
	int num, temp;
	for(int i = 0; i < n; ++i){
		for(int j = 0; j < m; ++j){
			cin>>s;
			num = -1;
			temp = 1;
			for(int k = 0; k < s.size(); ++k){
				if(s[k] >= '0' && s[k] <= '9'){
					if (num == -1){
						num = s[k] - '0';
					}
					else{
						num = num * 10 + s[k] - '0';
					}
				}
				else{
					if(num != -1){
						map[i][j][0]++;
						map[i][j][temp++] = num;
						num = -1;
					}
				}
			}
			map[i][j][0] = temp - 1;
		}
	}
	for (accept_num = 0; accept_num < 51; accept_num++) {
            cin >> accept[accept_num];
            if (accept[accept_num] == -1) break;
    } 	
}
int main(){
	alphabet[0] = 'A';
	for(int i = 1;i < 27; ++i){
		alphabet[i] = 97 + i;
	}
	while((cin>>n>>m) && n != 0 && m != 0){
		init(n,m);
		while(1){
			int state2;
			cin>>s;
			check = 0;
			if(s == "#")break;
			memset(state, 0, sizeof(state));
			statenum = 1;
			state1num = 0;
			for(int i = 0; i< s.size(); ++i){
				for(int j = 0; j < statenum; ++j){
					for(int k = 0; k < map[state[j]][0][0]; ++k){
						state2 = map[state[j]][0][k+1];
						bool get = 0;
						for (int l = 0; l < statenum; ++l){
							if(state[l] == state2)get = 1;
						}
						if(!get){
							state[statenum++] = state2;
						}
					}
					for(int k = 0; k < map[state[j]][s[i]-96][0]; ++k){
						state2 = map[state[j]][s[i]-96][k+1];
						bool get = 0;
						for(int l = 0; l < state1num; ++l){
							if(state[l] == state2)get = 1;
						}
						if(!get){
							state1[state1num++] = state2;
						}
					}
				}
				for(int j = 0; j < state1num; ++j){
					state[j] = state1[j];
				}
				statenum = state1num;
				state1num = 0;
				for(int j = 0; j < statenum; ++j){
					int state2;
					for(int k = 0; k < map[state[j]][0][0]; ++k){
						state2 = map[state[j]][0][k+1];
						bool get = 0;
						for (int l = 0; l < statenum; ++l){
							if(state[l] == state2)get = 1;
						}
						if(!get){
							state[statenum++] = state2;
						}
					}
				}
			}
			for(int i = 0; i < accept_num; ++i){
				for (int j = 0; j < statenum; ++j){
					if(state[j] == accept[i]){
						check = 1;
						break;
					}
				}
			}
			if(check){
				cout<<"YES"<<endl;
			}
			else{
				cout<<"NO"<<endl;
			}	
		}
	}
	return 0;
} 

相關文章