确定性有限自动机(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的倍数