División basada en DFA

El autómata finito determinista (DFA) se puede utilizar para comprobar si un número «num» es divisible por «k» o no. Si el número no es divisible, el resto también se puede obtener mediante DFA.
Consideramos la representación binaria de ‘num’ y construimos un DFA con k estados. El DFA tiene una función de transición para 0 y 1. Una vez que se crea el DFA, procesamos ‘num’ sobre el DFA para obtener el resto.
Veamos un ejemplo. Supongamos que queremos comprobar si un número dado ‘num’ es divisible por 3 o no. Cualquier número se puede escribir en la forma: num = 3*a + b donde ‘a’ es el cociente y ‘b’ es el resto. 
Para 3, puede haber 3 estados en DFA, cada uno correspondiente al resto 0, 1 y 2. Y cada estado puede tener dos transiciones correspondientes a 0 y 1 (considerando la representación binaria de ‘num’ dado). 
La función de transición F(p, x) = q dice que al leer el alfabeto x, pasamos del estado p al estado q. Llamemos a los estados como 0, 1 y 2. El estado inicial siempre será 0. El estado final indica el resto. Si el estado final es 0, el número es divisible.
 

En el diagrama anterior, el estado de doble círculo es el estado final.
1. Cuando estamos en el estado 0 y leemos 0, nos quedamos en el estado 0. 
2. Cuando estamos en el estado 0 y leemos 1, pasamos al estado 1, ¿por qué? El número así formado (1) en decimal da resto 1. 
3. Cuando estamos en el estado 1 y leemos 0, pasamos al estado 2, ¿por qué? El número así formado (10) en decimal da resto 2. 
4. Cuando estamos en el estado 1 y leemos 1, pasamos al estado 0, ¿por qué? El número así formado (11) en decimal da resto 0. 
5. Cuando estamos en el estado 2 y leemos 0, pasamos al estado 1, ¿por qué? El número así formado (100) en decimal da resto 1. 
6. Cuando estamos en el estado 2 y leemos 1, permanecemos en el estado 2, ¿por qué? El número así formado (101) en decimal da el resto 2.
La tabla de transición se parece a la siguiente: 
 

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

Comprobemos si 6 es divisible por 3. 
La representación binaria de 6 es 110 
estado = 0 
1. estado=0, leemos 1, nuevo estado=1 
2. estado=1, leemos 1, nuevo estado=0 
3. estado=0, leemos 0, nuevo estado= 0 
Como el estado final es 0, el número es divisible por 3.
Tomemos otro número de ejemplo como 4 
estado=0 
1. estado=0, leemos 1, nuevo estado=1 
2. estado=1, leemos 0, nuevo estado=2 
3. estado=2, leemos 0, nuevo estado=1 
Dado que el estado final no es 0, el número no es divisible por 3. El resto es 1.
Tenga en cuenta que el estado final da el resto. 
Podemos extender la solución anterior para cualquier valor de k. Para un valor k, los estados serían 0, 1,…. , k-1. ¿Cómo calcular la transición si el equivalente decimal de los bits binarios vistos hasta ahora cruza el rango k? Si estamos en el estado p, hemos leído p (en decimal). Ahora leemos 0, el nuevo número de lectura se convierte en 2*p. Si leemos 1, el nuevo número de lectura se convierte en 2*p+1. El nuevo estado se puede obtener restando k de estos valores (2p o 2p+1) donde 0 <= p < k. 
Basado en el enfoque anterior, el siguiente es el código de trabajo: 
 

C++

#include <bits/stdc++.h>
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 <stdio.h>
#include <stdlib.h>
 
// 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 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;
}

Javascript

// JavaScript program to implement the approach
 
// Function to build DFA for divisor k
function preprocess(k, Table)
{
    let trans0, trans1;
 
    // The following loop calculates the
    // two transitions for each state,
    // starting from state 0
    for (let 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
function isDivisibleUtil(num, state, Table)
{
    // process "num" bit by bit
    // from MSB to LSB
    if (num != 0)
    {
        state = isDivisibleUtil(num >> 1, state, Table);
        state = Table[state][num & 1];
    }
    return state;
}
 
// The main function that divides 'num'
// by k and returns the remainder
function isDivisible (num, k)
{
    // Allocate memory for transition table.
    // The table will have k*2 entries
    Table = new Array(k);
    for (let i = 0; i < k; i++)
        Table[i] = [0, 0];
 
    // Fill the transition table
    preprocess(k, Table);
 
    // Process ‘num’ over DFA and
    // get the remainder
    let state = 0;
    state = isDivisibleUtil(num, state, Table);
 
    // Note that the final value
    // of state is the remainder
    return state;
}
 
// Driver Code
let num = 47; // Number to be divided
let k = 5; // Divisor
 
let remainder = isDivisible (num, k);
 
if (remainder == 0)
    console.log("Divisible");
else
    console.log("Not Divisible: Remainder is " + remainder);
 
// This is code contributed by phasing17

Python3

# Python3 program to implement the approach
 
# Function to build DFA for divisor k
 
 
def preprocess(k, Table):
 
    # The following loop calculates the
    # two transitions for each state,
    # starting from state 0
    for state in range(k):
 
        # Calculate next state for bit 0
        trans0 = state << 1
        if (trans0 < k):
            Table[state][0] = trans0
        else:
            Table[state][0] = trans0 - k
 
        # Calculate next state for bit 1
        trans1 = (state << 1) + 1
 
        if trans1 < k:
            Table[state][1] = trans1
        else:
            Table[state][1] = trans1 - k
 
 
# A recursive utility function that
# takes a 'num' and DFA (transition
# table) as input and process 'num'
# bit by bit over DFA
def isDivisibleUtil(num, state, Table):
    # process "num" bit by bit
    # from MSB to LSB
    if (num != 0):
        state = isDivisibleUtil(num >> 1, state, Table)
        state = Table[state][num & 1]
    return state
 
 
# The main function that divides 'num'
# by k and returns the remainder
def isDivisible(num, k):
 
    # Allocate memory for transition table.
    # The table will have k*2 entries
    Table = [None for i in range(k)]
    for i in range(k):
        Table[i] = [0, 0]
 
    # Fill the transition table
    preprocess(k, Table)
 
    # Process ‘num’ over DFA and
    # get the remainder
    state = 0
    state = isDivisibleUtil(num, state, Table)
 
    # Note that the final value
    # of state is the remainder
    return state
 
 
# Driver Code
 
num = 47  # Number to be divided
k = 5  # Divisor
 
remainder = isDivisible(num, k)
 
if (remainder == 0):
    print("Divisible")
else:
    print("Not Divisible: Remainder is", remainder)
 
 
# This is code contributed by phasing17

Producción: 
 

Not Divisible: Remainder is 2

Complejidad de tiempo: O(k)

La división basada en DFA puede ser útil si tenemos una secuencia binaria como entrada y queremos verificar la divisibilidad del valor decimal de la secuencia en cualquier momento.
Artículos relacionados:  
Verificar la divisibilidad en un flujo binario  
Verificar si un flujo es múltiplo de 3
Este artículo fue compilado por Aashish Barnwal y revisado por el equipo de GeeksforGeeks. Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *