Cómo encontrar el subconjunto contiguo de suma máxima utilizando un método de divide y vencerás

Divida la entrada por la mitad y considere que la submatriz de suma máxima puede provenir de tres lugares:

  1. Está completamente en la mitad izquierda.
  2. Está completamente en la mitad derecha.
  3. Consiste en una cierta cantidad de elementos más a la derecha de la mitad izquierda y una cierta cantidad de elementos más a la izquierda de la mitad derecha.

Supongamos que resuelve el problema recursivamente en las mitades izquierda y derecha. Entonces conocerá las mejores submatrices que puede obtener que están completamente en cada una de las mitades, para los puntos 1 y 2 anteriores.

Para 3, notamos que el número de elementos a tomar de la mitad izquierda y la mitad derecha debe elegirse independientemente (es decir, ambos deben elegirse para maximizar su contribución a la suma). Entonces, simplemente estamos buscando la suma de prefijos más grande en la submatriz derecha, y la suma de sufijos más grande en la submatriz izquierda, que pueden resolverse trivialmente en O (n) tiempo y O (1) espacio.

Entonces es fácil comparar las opciones 1, 2 y 3, y encontrar el máximo.

La recurrencia para la complejidad del tiempo es T (n) = 2T (n / 2) + O (n), lo que nos da T (n) = O (n log n).

Podemos hacer una optimización para resolver este problema en O (n). Si regresamos, para cada caso recursivo, no solo la ubicación del subarreglo óptimo y su suma, sino también la suma total de la matriz y los prefijos y sufijos más grandes, cada caso recursivo solo necesita hacer el trabajo O (1):

full.maxPrefix = max (left.maxPrefix, left.sum + right.maxPrefix)

full.maxSuffix = max(right.maxSuffix, right.sum + left.maxSuffix)

full.sum = left.sum + right.sum

full.maxInner = max(left.maxInner, right.maxInner, left.maxSuffix + right.maxPrefix)

Debería almacenar un poco más de información de contabilidad si desea encontrar la posición de la submatriz máxima también.

Con todos los cálculos para un solo caso que se ejecuta en O (1), la recurrencia ahora es T (n) = 2T (n / 2) + O (1), lo que produce O (n).

Esto parece un método complicado en comparación con la solución estándar O (n) para este problema. Sin embargo, este tipo de enfoque es lo que se necesita, en combinación con un árbol de segmentos, para resolver la versión dinámica de este problema.

La versión dinámica tendría el siguiente enunciado del problema: cree una estructura de datos que, después de un preprocesamiento inicial, pueda admitir set(index, value) y getCurrentMaxSubarraySum() en tiempo O (log n) para ambos. En otras palabras, los elementos arbitrarios de la matriz pueden cambiar y la suma máxima de subarreglos necesita ser recalculada eficientemente entre los cambios.

Gracias por A2A, Rahul Kumar

Aquí, debe encontrar la suma máxima de subconjuntos contiguos. Ahora, cualquier submatriz estará definida por dos índices que están limitados por el tamaño de la matriz. Entonces, el algoritmo de fuerza bruta sería O (n ^ 2)

Algoritmo:

Divide la matriz en dos mitades.

Ahora hay 3 posibilidades de 2 índices de submatriz máxima:

  1. Ambos están en el lado izquierdo del punto medio (recursivo). – En 2)
  2. Ambos están en el lado derecho del punto medio (Recursivo). – En 2)
  3. Ambos están en el lado opuesto del punto medio. – ???

Entonces, su respuesta sería el máximo de las tres posibilidades.

Entonces, su código debería verse así:

int maxsum (int a [], int start, int end)
{
{Condición base} // algo así como (final-inicio) <2
int mid = (inicio + fin) / 2;
int m1 = maxsum (a, inicio, medio);
int m2 = maxsum (a, mid + 1, end);
int m3 = maxopposite (a, inicio, medio, fin);
retorno max (m1, m2, m3);
}

(Se ha seguido la notación C ++)

Ahora, la complejidad del tiempo:

T (n) = 2 * T (n / 2) + O (máximo opuesto).

Si la función “maxopposite” es O (n ^ 2), entonces T (n) = O (n ^ 2). Pero si logramos hacer que sea O (n), entonces T (n) = O (nlogn).

Ahora, función maxopposite:

Ve al lado izquierdo desde el punto medio, almacena la suma más alta posible hasta ahora y actualízala si es necesario en cada iteración. Luego haz lo mismo en el lado derecho del punto medio. Y agrega ambos y devuélvelo.

Entonces, el pseudo bacalao debería verse así:

int maxopposite (int a [], int start, int mid, int end)
{
int leftsum = 0, leftbest = 0;
for (int i = mid-1; i> = start; i–)
{
leftsum + = a [i];
if (leftbest leftbest = leftsum;
}
int rightsum = 0, rightbest = 0;
para (int i = mid + 1; i <= end; i ++)
{
rightsum + = a [i];
if (rightbest rightbest = rightsum;
}
return leftbest + rightbest + a [medio];
}

Para mayor referencia y explicación detallada:

Divide y vencerás | Conjunto 3 (Suma máxima de subarrays) – GeeksforGeeks

Esta técnica no proporciona la solución más óptima para este problema. También hay una solución de programación dinámica que es de O (n). Aquí está el enlace:

Subarray contiguo de suma más grande – GeeksforGeeks

Espero que esto ayude.

More Interesting

¿Por qué deberíamos instanciar una matriz en una línea diferente?

¿Cuáles son algunos problemas prácticos en los que no se puede evitar el uso de algoritmos con big-O muy grande?

Estoy comenzando un proyecto de clasificación de picos, ¿dónde encuentro datos sin procesar y / o simulados?

¿Por qué no usamos el aprendizaje automático para mejorar los modelos climáticos?

Recientemente me enamoré de las estructuras de datos y algoritmos. ¿Qué idioma (s) y qué rama (s) de matemáticas le servirían mejor y qué tipo de trabajos de entrada debería buscar una vez que lo lleve a un nivel decente, unos 4-6 meses después?

¿Existe algún enlace de los algoritmos o técnicas más utilizados en la programación competitiva?

¿Qué son las estrategias de diseño de algoritmos?

¿Cuál es la forma correcta de escribir un algoritmo? ¿Podemos usar la sintaxis del lenguaje en el que estamos escribiendo?

¿Cómo se puede resolver el coeficiente binomial usando programación dinámica y tabla hash?

¿Habrá diferentes algoritmos para implementar la inserción y eliminación de una estructura de datos como b árboles?

¿Cómo podemos verificar si un punto (digamos el origen) se encuentra en un casco convexo 6-D (o ND) y qué tan lejos está el punto de cualquiera de los lados (facetas) del casco convexo?

¿Cuál es la implementación más rápida del árbol de búsqueda binario? (auto-equilibrio)

¿Cuál es el algoritmo que utilizan los ferrocarriles indios para la confirmación de un boleto de espera? ¿Cuál es la mejor manera de confirmar un boleto cuando hay una gran lista de espera?

¿Es CodeChef la opción correcta para practicar problemas algorítmicos hoy en día?

¿Cuáles son las ventajas de usar la notación (0,1) en el sistema binario?