实验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 ", cnt, sum, 0); for(int i = 0, j = 0; i < cnt; i++) { if(ac[i]) { if(j) printf(" "); printf("%d", i); j++; } } printf(" "); for(int i = 0; i < cnt; i++) { if(i) printf(" "); printf("%d", change[lft[i]]); } printf(" "); for(int i = 0; i < cnt; i++){ if(i) printf(" "); printf("%d", change[rgt[i]]); } printf(" "); } return 0; }