實驗C----NFA轉換為DFA | ||||||||||||||||||||||||||||||
Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:65536KB | ||||||||||||||||||||||||||||||
Total submit users: 74, Accepted users: 58 | ||||||||||||||||||||||||||||||
Problem 13120 : Special judge | ||||||||||||||||||||||||||||||
Problem description | ||||||||||||||||||||||||||||||
有限狀態自動機(FSM "finite state machine" 或者FSA "finite state automaton" )是為研究有限內存的計算過程和某些語言類而抽象出的一種計算模型。有限狀態自動機擁有有限數量的狀態,每個狀態可以遷移到零個或多個狀態,輸入字串決定執行哪個狀態的遷移。有限狀態自動機可以表示為一個有向圖。有限狀態自動機是自動機理論的研究對象。 定義:有限狀態自動機(FA—finite automaton)是一個五元組: ? M=(Q, Σ, δ, q0, F) · 其中, ? Q——狀態的非空有窮集合。?q∈Q,q稱為M的一個狀態。 ? Σ——輸入字母表。 ? δ——狀態轉移函數,有時又叫作狀態轉換函數或者移動函數,δ:Q×Σ→Q,δ(q,a)=p。 ? q0——M的開始狀態,也可叫作初始狀態或啟動狀態。q0∈Q。 ? F——M的終止狀態集合。F被Q包含。任給q∈F,q稱為M的終止狀態。 非確定有限狀態自動機(NFA)與確定有限狀態自動機(DFA)的唯一區別是它們的轉移函數不同。確定有限狀態自動機對每一個可能的輸入只有一個狀態的轉移。非確定有限狀態自動機對每一個可能的輸入可以有多個狀態轉移,接受到輸入時從這多個狀態轉移中非確定地選擇一個。下圖是一個非確定性有限狀態自動機(NFA)的例子: ![]() 轉移函數δ定義自下列狀態轉移表:
你的任務,是要將一個給定的NFA轉換為一個完全等價的DFA(有限狀態自動機等價的意思是識別相同的語言)。這里我們約定自動機識別的字符集為{0,1},初始狀態集合為Q0,狀態集為{q0,q1,…,qn-1}。 |
||||||||||||||||||||||||||||||
Input | ||||||||||||||||||||||||||||||
輸入第一行只有一個正整數t,表示有t個測試數據(意味着t個NFA)t≤10; |
||||||||||||||||||||||||||||||
Output | ||||||||||||||||||||||||||||||
對於每個NFA,輸出四行表示與之等價的DFA。輸出格式如下: |
||||||||||||||||||||||||||||||
Sample Input | ||||||||||||||||||||||||||||||
1 4 1 8 1 4 0 8 7 8 8 8 |
||||||||||||||||||||||||||||||
Sample Output | ||||||||||||||||||||||||||||||
16 8 1 8 9 10 11 12 13 14 15 0 1 4 5 0 1 4 5 8 9 12 13 8 9 12 13 0 7 8 15 8 15 8 15 8 15 8 15 8 15 8 15 |
||||||||||||||||||||||||||||||
Judge Tips | ||||||||||||||||||||||||||||||
樣例中的NFA如圖一所示 與某個NFA等價的DFA不一定是唯一的,比如和圖一等價的DFA可以是樣例的解答,也可以是如下的DFA 4 1 0 3 0 2 0 3 1 3 3 3 本題會使用special judge,只要是符合條件的解答都可以接受(Accept)。 |
1、算法設計思路
狀態集合的子集合,采用二進制(特征)串的方式,一個子集中包含該狀態,對應的特征串就為1,否則為0,比如上面狀態集合的子集{q0q1q2},其特征串就是0111,而子集{q0},其特征串就是0001。將對應的特征串轉換為十進制的數字,得到轉移函數δ。
2、實驗總結
在轉化的過程中經NFA中狀態矩陣中的每一個狀態的集合映射到DFA中的一個狀態。即NFA中的狀態子集為一個DFA中的狀態;只要NFA狀態子集中有一個為接受態,相應的映射的DFA中的狀態就為接受態
3、AC代碼
#include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<cmath> #define M 99999 using namespace std; int ans[M]; int one[M]; int zero[M]; int lft[M]; int rgt[M]; int change[M]; bool vis[M]; bool ac[M]; int cnt, n, q, f; int index(int p) { int x = 1; if(p == 1) return 0; int i = 0; while(++i) { x <<= 1; if(p == x) return i; } return 0; } int mege(int a, int b) { while(b) { int x = b&(-b); if(!(a&x)) a ^= x; b ^= x; } return a; } void dfs(int p) { ans[cnt] = p; int lsum = 0, rsum = 0; while(p) { int x = p&(-p); int y = index(x); lsum = mege(lsum, zero[y]); rsum = mege(rsum, one[y]); p ^= x; } lft[cnt] = lsum; rgt[cnt] = rsum; cnt++; if(!vis[lsum]) vis[lsum] = 1, dfs(lsum); if(!vis[rsum]) vis[rsum] = 1, dfs(rsum); } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%d%d", &n, &q, &f); for(int i = 0; i < n; i++) scanf("%d", &zero[i]); for(int i = 0; i < n; i++) scanf("%d", &one[i]); cnt = 0; memset(vis, 0, sizeof(vis)); memset(ac, 0, sizeof(ac)); vis[q] = 1; dfs(q); int sum = 0; for(int i = 0; i < cnt; i++) if(ans[i]&f) ac[i] = 1, sum++; for(int i = 0; i < cnt; i++) change[ans[i]] = i; printf("%d %d %d\n", cnt, sum, 0); for(int i = 0, j = 0; i < cnt; i++) { if(ac[i]) { if(j) printf(" "); printf("%d", i); j++; } } printf("\n"); for(int i = 0; i < cnt; i++) { if(i) printf(" "); printf("%d", change[lft[i]]); } printf("\n"); for(int i = 0; i < cnt; i++){ if(i) printf(" "); printf("%d", change[rgt[i]]); } printf("\n"); } return 0; }