知识点 - 确定有穷自动机

本文介绍确定有穷自动机(DFA)的基本概念及其在字符串匹配和文本分析中的应用。通过实例解析了如何使用DFA判断二进制数是否为3的倍数,并详细阐述了解决字符矩阵旋转与翻转问题的算法思路。

知识点 - 确定有穷自动机 DFA Deterministic finite automaton

解决问题类型:

求字符矩阵进行1e6次旋转(2个方向)和翻转(4个方向)后的状态。

字符串匹配、文本分析。

定义

确定有穷自动机M由五个元素组成: M = ( Q , Σ , δ , q 0 , F ) M=(Q,\Sigma,\delta,q_0,F) M=(QΣδq0F)其中

Q : Q: Q状态的集合;

q 0 : q 0 ∈ Q q_0:q_0\in Q q0:q0Q是唯一的初始状态;

F : F ⊆ Q F:F\subseteq Q F:FQ是终止状态(accept state)集合。

Σ : Σ: Σ输入的字母表;

δ : \delta: δ转换函数,是在 Q × Σ → Q Q×Σ→Q Q×ΣQ上的映射.

e.g.判断二进制是否是3的倍数的自动机

0,11, 110, 1001, 1100, 1111, 10010, 10101, 11000, 11011, 11110, 100001, 100100, 100111, 101010, 101101, 110000, 110011, 110110, 111001, 111100, 111111,

在这里插入图片描述

状态是满足特定条件的二进制数,字母表是01。

每次读一个符号,DFA就确定地从一个状态转移到另一个状态。转移用箭头表示。

初始状态 S 0 S_0 S0,它被一个没有起点的箭头所指。

终止状态也是 S 0 S_0 S0,它用两个圈表示。

复杂度:

O ( N + M ) O(N+M) O(N+M)N是指令串的长度,M是单次转移的复杂度

例题

Rotating Display : 求一个字符矩阵进行1e6次旋转(< >2个方向)和翻转(- |/ \4个方向)后的状态。

我们只需要2个转移(比如|,<)就能实现所有操作,于是我们得到八种不同的状态,画出下面的图。

在这里插入图片描述

代码

/**
 * CTU Open 2016
 * Problem Solution: Display
 * 
 * @author Pavel Strnad
 */
 
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

// MxM
int M;
int state = 0;

vector<string> split(const char *str, char c = ' ')
{
    vector<string> result;
    do
    {
        const char *begin = str;
        while(*str != c && *str)
            str++;
        result.push_back(string(begin, str));
    } while (0 != *str++);
    return result;
}

void edgeRR() {
    state++;
    if(state == 4) state = 0;
    if(state == 15) state = 11;
}

void edgeRL() {
    state--;
    if(state == -1) state = 3;
    if(state == 10) state = 14;
}

void edgeFH() {
    switch(state) {
	case 0: state = 11; break;
	case 1: state = 14; break;
        case 2: state = 13; break;
        case 3: state = 12; break;
        case 11: state = 0; break;
        case 12: state = 3; break;
        case 13: state = 2; break;
        case 14: state = 1; break;
    }
}

char arr1[] = {'^','>','v','<'};
char arr2[] = {'/','\\', '/','\\'};
char arr3[] = {'|','-', '|','-'};

char getSymbolRL(char in) {
    for(int i = 0; i<4; i++) {
        int pos = (i-1)%4;
        pos = pos < 0 ? pos + 4 : pos;
	if(arr1[i] == in) {
	    return arr1[pos];
	}
	if(arr2[i] == in) {
	    return arr2[pos];
	}
	if(arr3[i] == in) {
	    return arr3[pos];
	}
    }
    return in;
}


char mh1[] = {'^','v'};
char mh2[] = {'/','\\'};

char getSymbolFH(char in) {
    for(int i = 0; i<2; i++) {
        int pos = (i-1)%2;
        pos = pos < 0 ? pos + 2 : pos;
	if(mh1[i] == in) {
	    return mh1[pos];
	}
	if(mh2[i] == in) {
	    return mh2[pos];
	}
    }
    return in;
}


void RL(char *d)
{
    for (int x = 0; x < M / 2; x++)
    {
        for (int y = x; y < M-x-1; y++)
        {
            // store current cell in temp variable
            char temp = getSymbolRL(*(d + x * (M + 1) + y));
 
            // move values from right to top
            *(d + x * (M + 1) + y) = getSymbolRL(*(d + y * (M + 1) + M-1-x));
 
            // move values from bottom to right
            *(d + y * (M + 1) + M-1-x) = getSymbolRL(*(d + (M-1-x) *(M+1) + M-1-y));
 
            // move values from left to bottom
            *(d + (M-1-x) * (M+1) + M-1-y) = getSymbolRL(*(d + (M-1-y) * (M+1) + x));
 
            // assign temp to left
            *(d + (M-1-y) * (M+1) + x) = temp;
        }
    }
    if(M%2==1) {
	*(d + (M/2) * (M+1) + M/2) = getSymbolRL(*(d + (M/2) * (M+1) + M/2));
    }
}

void FH(char *d) {
    for(int x = 0; x < M/2; x++) {
	for(int y = 0; y < M; y++) {
	    char temp = getSymbolFH(*(d + x * (M + 1) + y));
	    *(d + x * (M + 1) + y) = getSymbolFH(*(d + (M - 1 - x) * (M + 1) + y));
	    *(d + (M - 1 - x) * (M + 1) + y) = temp;	
	}
    }
    if(M%2==1) {
	for(int x = 0; x < M; x++) {
	    *(d + (M/2) * (M+1) + x) = getSymbolFH(*(d + (M/2) * (M+1) + x));
	}
    }

}

void transform(char *d) {
    switch(state) {
	case 0: return;
	case 1: RL(d);
	case 2: RL(d);
        case 3: RL(d); return;
        case 11: FH(d); return;
        case 12: FH(d); RL(d); RL(d); RL(d); return;
        case 13: FH(d); RL(d); RL(d); return;
        case 14: FH(d); RL(d); return;
	default: cout << "Unknown state" << endl;
    }
    return;
}

int main() {
    string line;
    while(getline(cin, line)) {
        state = 0;
	stringstream ss(line);
	ss >> M;
	char display[M][M+1];
	for(int i=0; i < M; i++) {
	    cin.getline(display[i],M+1);
	}
	getline(cin,line);
	for(string s : split(line.c_str())) {
	   if(s.compare("<")==0) {
		edgeRL();
	   }
	   if(s.compare(">")==0) {
		edgeRR();
	   }
	   if(s.compare("-")==0) {
		edgeFH();
	   }
	   if(s.compare("|")==0) {
		edgeFH(); edgeRR(); edgeRR();
	   }	   
	   if(s.compare("\\")==0) {
		edgeFH(); edgeRR();
	   }	   
	   if(s.compare("/")==0) {
		edgeFH(); edgeRL();
	   }	   
	}
	transform((char *) display);
	for(int i=0;i<M;i++) cout << display[i] << endl;
    }
    return 0;
}
1. 实验内容 每一个正规集都可以由一个状态数最少的DFA所识别,这个DFA是唯一的(不考虑同构的情况)。任意给定的一个DFA,根据以下算法设计一个C程序,将该DFA 化简为与之等价的最简DFA。 2. 实验设计分析 2.1 实验设计思路 根据实验指导书和书本上的相关知识,实现算法。 2.2 实验算法 (1)构造具有两个组的状态集合的初始划分I:接受状态组 F 和非接受状态组 Non-F。 (2)对I采用下面所述的过程来构造新的划分I-new. For I 中每个组G do Begin 当且仅当对任意输入符号a,状态s和读入a后转换到I的同一组中; /*最坏情况下,一个状态就可能成为一个组*/ 用所有新形成的小组集代替I-new中的G; end (3)如果I-new=I,令I-final=I,再执行第(4)步,否则令I=I=new,重复步骤(2)。 (4)在划分I-final的每个状态组中选一个状态作为该组的代表。这些代表构成了化简后的DFA M'状态。令s是一个代表状态,而且假设:在DFA M中,输入为a时有从s到t转换。令t所在组的代表是r,那么在M’中有一个从s到r的转换,标记为a。令包含s0的状态组的代表是M’的开始状态,并令M’的接受状态是那些属于F的状态所在组的代表。注意,I-final的每个组或者仅含F中的状态,或者不含F中的状态。 (5)如果M’含有死状态(即一个对所有输入符号都有刀自身的转换的非接受状态d),则从M’中去掉它;删除从开始状态不可到达的状态;取消从任何其他状态到死状态的转换。 。。。。。。
1. 实验内容 每一个正规集都可以由一个状态数最少的DFA所识别,这个DFA是唯一的(不考虑同构的情况)。任意给定的一个DFA,根据以下算法设计一个C程序,将该DFA 化简为与之等价的最简DFA。 2. 实验设计分析 2.1 实验设计思路 根据实验指导书和书本上的相关知识,实现算法。 2.2 实验算法 (1)构造具有两个组的状态集合的初始划分I:接受状态组 F 和非接受状态组 Non-F。 (2)对I采用下面所述的过程来构造新的划分I-new. For I 中每个组G do Begin 当且仅当对任意输入符号a,状态s和读入a后转换到I的同一组中; /*最坏情况下,一个状态就可能成为一个组*/ 用所有新形成的小组集代替I-new中的G; end (3)如果I-new=I,令I-final=I,再执行第(4)步,否则令I=I=new,重复步骤(2)。 (4)在划分I-final的每个状态组中选一个状态作为该组的代表。这些代表构成了化简后的DFA M'状态。令s是一个代表状态,而且假设:在DFA M中,输入为a时有从s到t转换。令t所在组的代表是r,那么在M’中有一个从s到r的转换,标记为a。令包含s0的状态组的代表是M’的开始状态,并令M’的接受状态是那些属于F的状态所在组的代表。注意,I-final的每个组或者仅含F中的状态,或者不含F中的状态。 (5)如果M’含有死状态(即一个对所有输入符号都有刀自身的转换的非接受状态d),则从M’中去掉它;删除从开始状态不可到达的状态;取消从任何其他状态到死状态的转换。 。。。。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Best KeyBoard

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值