📜  基于DFA的部门

📅  最后修改于: 2021-04-26 10:39:58             🧑  作者: Mango

确定性有限自动机(DFA)可用于检查数字“ num”是否可被“ k”整除。如果数字不可分割,则还可以使用DFA获得余数。

我们考虑’num’的二进制表示形式,并使用k个状态构建DFA。 DFA同时具有0和1的转换函数。一旦构建了DFA,我们就会在DFA上处理“ num”以获取余数。

让我们来看一个例子。假设我们要检查给定的数字“ num”是否可以被3整除。任何数字都可以用以下形式写:num = 3 * a + b其中“ a”是商,“ b”是余数。
对于3,在DFA中可以有3个状态,每个状态对应于余数0、1和2。每个状态可以具有对应于0和1的两个转换(考虑给定’num’的二进制表示)。
转换函数F(p,x)= q表示在读取字母x时,我们从状态p移至状态q。让我们将状态分别命名为0、1和2。初始状态将始终为0。最终状态指示余数。如果最终状态为0,则数字是可整除的。

在上图中,双圈状态是最终状态。

1.当我们处于状态0并读取0时,我们保持状态0。
2.当我们处于状态0并读取1时,我们转到状态1,为什么呢?如此形成的数字(1)以十进制表示余数1。
3.当我们处于状态1并读为0时,我们移至状态2,为什么呢?如此形成的数字(10)以十进制表示余数2。
4.当我们处于状态1并读取1时,我们移至状态0,为什么呢?如此形成的数字(11)以十进制表示,余数为0。
5.当我们处于状态2并读为0时,我们移至状态1,为什么?如此形成的数字(100)以十进制表示余数1。
6.当我们处于状态2并读取1时,我们仍然处于状态2,为什么?如此形成的数字(101)以十进制gves余数2表示。

过渡表如下所示:

state   0   1
_____________
 0      0   1
 1      2   0
 2      1   2

让我们检查6是否可被3整除吗?
6的二进制表示形式是110
状态= 0
1.状态= 0,我们读为1,新状态= 1
2.状态= 1,我们读取1,新状态= 0
3.状态= 0,我们读为0,新状态= 0
由于最终状态为0,因此该数字可以被3整除。

让我们以另一个示例数字为4
状态= 0
1.状态= 0,我们读为1,新状态= 1
2.状态= 1,我们读取为0,新状态= 2
3.状态= 2,我们读取0,新状态= 1
由于最终状态不为0,因此该数字不能被3整除。余数为1。

请注意,最终状态给出了余数。

我们可以将上述解决方案扩展为k的任何值。对于值k,状态将为0、1,…。 ,k-1。如果到目前为止所看到的二进制位的十进制等效值超过范围k,如何计算跃迁?如果我们处于状态p,则已读取p(十进制)。现在我们读0,新的读数变成2 * p。如果我们读为1,则新的读数变为2 * p + 1。可以通过从这些值(2p或2p + 1)减去k来获得新状态,其中0 <= p 基于上述方法,以下是工作代码:

C++
#include 
using namespace std;
  
// Function to build DFA for divisor k 
void preprocess(int k, int Table[][2]) 
{ 
    int trans0, trans1; 
  
    // The following loop calculates the 
    // two transitions for each state, 
    // starting from state 0 
    for (int state = 0; state < k; ++state) 
    { 
        // Calculate next state for bit 0 
        trans0 = state << 1; 
        Table[state][0] = (trans0 < k) ? 
                                trans0 : trans0 - k; 
  
        // Calculate next state for bit 1 
        trans1 = (state << 1) + 1; 
        Table[state][1] = (trans1 < k) ? 
                                trans1 : trans1 - k; 
    } 
} 
  
// A recursive utility function that 
// takes a 'num' and DFA (transition 
// table) as input and process 'num' 
// bit by bit over DFA 
void isDivisibleUtil(int num, int* state,
                     int Table[][2]) 
{ 
    // process "num" bit by bit
    // from MSB to LSB 
    if (num != 0) 
    { 
        isDivisibleUtil(num >> 1, state, Table); 
        *state = Table[*state][num & 1]; 
    } 
} 
  
// The main function that divides 'num' 
// by k and returns the remainder 
int isDivisible (int num, int k) 
{ 
    // Allocate memory for transition table. 
    // The table will have k*2 entries 
    int (*Table)[2] = (int (*)[2])malloc(k*sizeof(*Table)); 
  
    // Fill the transition table 
    preprocess(k, Table); 
  
    // Process ‘num’ over DFA and 
    // get the remainder 
    int state = 0; 
    isDivisibleUtil(num, &state, Table); 
  
    // Note that the final value 
    // of state is the remainder 
    return state; 
} 
  
// Driver Code
int main() 
{ 
    int num = 47; // Number to be divided 
    int k = 5; // Divisor 
  
    int remainder = isDivisible (num, k); 
  
    if (remainder == 0) 
        cout << "Divisible\n"; 
    else
        cout << "Not Divisible: Remainder is " 
             << remainder; 
  
    return 0; 
} 
  
// This is code is contributed by rathbhupendra


C
#include 
#include 
  
// Function to build DFA for divisor k
void preprocess(int k, int Table[][2])
{
    int trans0, trans1;
  
    // The following loop calculates the two transitions for each state,
    // starting from state 0
    for (int state=0; state>1, state, Table);
        *state = Table[*state][num&1];
    }
}
  
// The main function that divides 'num' by k and returns the remainder
int isDivisible (int num, int k)
{
    // Allocate memory for transition table. The table will have k*2 entries
    int (*Table)[2] = (int (*)[2])malloc(k*sizeof(*Table));
  
    // Fill the transition table
    preprocess(k, Table);
  
    // Process ‘num’ over DFA and get the remainder
    int state = 0;
    isDivisibleUtil(num, &state, Table);
  
    // Note that the final value of state is the remainder
    return state;
}
  
// Driver program to test above functions
int main()
{
    int num = 47; // Number to be divided
    int k = 5; // Divisor
  
    int remainder = isDivisible (num, k);
  
    if (remainder == 0)
        printf("Divisible\n");
    else
        printf("Not Divisible: Remainder is %d\n", remainder);
  
    return 0;
}


输出:

Not Divisible: Remainder is 2

如果我们将二进制流作为输入,并且希望随时检查流的十进制值是否可除,则基于DFA的除法将非常有用。

相关文章:
检查二进制流中的可除性
检查流是否为3的倍数