¿Por qué creé un hilo duplicado?
Creé este hilo después de leer La subsecuencia creciente más larga con K excepciones permitidas . Me di cuenta de que la persona que hacía la pregunta no había entendido realmente el problema, porque se refería a un enlace que resuelve el problema "Subarreglo de mayor aumento con un cambio permitido". Entonces, las respuestas que obtuvo fueron irrelevantes para el problema de LIS.
Descripción del problema
Supongamos que una matriz A se da con longitud N . Encuentre la subsecuencia creciente más larga con K excepciones permitidas.
Ejemplo
1) N = 9, K = 1
A = [3,9,4,5,8,6,1,3,7]
Respuesta: 7
Explicación:
La subsecuencia creciente más larga es: 3,4,5,8 (o 6), 1 (excepción), 3,7 -> total = 7
2) N = 11, K = 2
A = [5,6,4,7,3,9,2,5,1,8,7]
respuesta: 8
Lo que he hecho hasta ahora ...
Si K = 1, solo se permite una excepción. Si se usa el algoritmo conocido para calcular la subsecuencia de mayor aumento en O (NlogN) ( haga clic aquí para ver este algoritmo ), entonces podemos calcular el LIS a partir de A [0] a A [N-1] para cada elemento de la matriz R. guardar los resultados en una nueva matriz de L con un tamaño de N . Mirando el ejemplo n.1, la matriz L sería: L = [1,2,2,3,4,4,4,4,5].
Usando la lógica inversa, calculamos la matriz R , cada elemento del cual contiene la secuencia decreciente más larga actual de N-1 a 0.
El LIS con una excepción es solo sol = max (sol, L [i] + R [i + 1]), donde sol se inicializa como sol = L [N-1] . Entonces calculamos LIS desde 0 hasta un índice i (excepción), luego paramos e iniciamos un nuevo LIS hasta N-1 .
A=[3,9,4,5,8,6,1,3,7]
L=[1,2,2,3,4,4,4,4,5]
R=[5,4,4,3,3,3,3,2,1]
Sol = 7
-> explicación paso a paso:
init: sol = L[N]= 5
i=0 : sol = max(sol,1+4) = 5
i=1 : sol = max(sol,2+4) = 6
i=2 : sol = max(sol,2+3) = 6
i=3 : sol = max(sol,3+3) = 6
i=4 : sol = max(sol,4+3) = 7
i=4 : sol = max(sol,4+3) = 7
i=4 : sol = max(sol,4+2) = 7
i=5 : sol = max(sol,4+1) = 7
Complejidad: O (NlogN + NlogN + N) = O (NlogN)
porque las matrices R, L necesitan tiempo NlogN para calcular y también necesitamos Θ (N) para encontrar sol .
Código para k = 1 problema
#include <stdio.h>
#include <vector>
std::vector<int> ends;
int index_search(int value, int asc) {
int l = -1;
int r = ends.size() - 1;
while (r - l > 1) {
int m = (r + l) / 2;
if (asc && ends[m] >= value)
r = m;
else if (asc && ends[m] < value)
l = m;
else if (!asc && ends[m] <= value)
r = m;
else
l = m;
}
return r;
}
int main(void) {
int n, *S, *A, *B, i, length, idx, max;
scanf("%d",&n);
S = new int[n];
L = new int[n];
R = new int[n];
for (i=0; i<n; i++) {
scanf("%d",&S[i]);
}
ends.push_back(S[0]);
length = 1;
L[0] = length;
for (i=1; i<n; i++) {
if (S[i] < ends[0]) {
ends[0] = S[i];
}
else if (S[i] > ends[length-1]) {
length++;
ends.push_back(S[i]);
}
else {
idx = index_search(S[i],1);
ends[idx] = S[i];
}
L[i] = length;
}
ends.clear();
ends.push_back(S[n-1]);
length = 1;
R[n-1] = length;
for (i=n-2; i>=0; i--) {
if (S[i] > ends[0]) {
ends[0] = S[i];
}
else if (S[i] < ends[length-1]) {
length++;
ends.push_back(S[i]);
}
else {
idx = index_search(S[i],0);
ends[idx] = S[i];
}
R[i] = length;
}
max = A[n-1];
for (i=0; i<n-1; i++) {
max = std::max(max,(L[i]+R[i+1]));
}
printf("%d\n",max);
return 0;
}
Generalización a K excepciones
He proporcionado un algoritmo para K = 1. No tengo idea de cómo cambiar el algoritmo anterior para que funcione con K excepciones. Me alegraría si alguien pudiera ayudarme.
( PS. Si es necesario, puedo proporcionar código para el algoritmo K = 1 en C ++.)
Respuestas:
Esta respuesta se modifica de mi respuesta a una pregunta similar en Computer Science Stackexchange.
El problema LIS con, a lo sumo, k excepciones admite un algoritmo O (n log² n) que utiliza la relajación lagrangiana. Cuando k es mayor que log n, esto mejora asintóticamente en el O (nk log n) DP, que también explicaremos brevemente.
Supongamos que DP [a] [b] denota la longitud de la subsecuencia creciente más larga con, como máximo, excepciones b (posiciones en las que el entero anterior es mayor que el siguiente) que termina en el elemento
ba. Este DP no está involucrado en el algoritmo, pero definirlo facilita la prueba del algoritmo.Por conveniencia, asumiremos que todos los elementos son distintos y que el último elemento de la matriz es su máximo. Tenga en cuenta que esto no nos limita, ya que solo podemos agregar m / 2n a la enésima apariencia de cada número, y agregar infinito a la matriz y restar uno de la respuesta. Sea V la permutación para la cual 1 <= V [i] <= n es el valor del i-ésimo elemento.
Para resolver el problema en O (nk log n), mantenemos la constante de que DP [a] [b] se ha calculado para b <j. Bucle j de 0 a k, en la iteración j calculando DP [a] [j] para todo a. Para hacer esto, repita i de 1 a n. Mantenemos el máximo de DP [x] [j-1] sobre x <i y una estructura de datos máxima de prefijo que en el índice i tendrá DP [x] [j] en la posición V [x] para x <i, y 0 en cualquier otra posición.
Tenemos DP [i] [j] = 1 + max (DP [i '] [j], DP [x] [j-1]) donde vamos sobre i', x <i, V [i '] < V [i]. El prefijo máximo de DP [x] [j-1] nos da el máximo de términos del segundo tipo, y la consulta de la estructura de datos máxima de prefijo para el prefijo [0, V [i]] nos da el máximo de términos del primer tipo. Luego actualice la estructura de datos de prefijo máximo y prefijo máximo.
Aquí hay una implementación en C ++ del algoritmo. Tenga en cuenta que esta implementación no asume que el último elemento de la matriz es su máximo, o que la matriz no contiene duplicados.
Ahora volveremos al algoritmo O (n log² n). Seleccione un número entero 0 <= r <= n. Defina DP '[a] [r] = max (DP [a] [b] - rb), donde se toma el máximo b, MAXB [a] [r] como el máximo b tal que DP' [a] [ r] = DP [a] [b] - rb, y MINB [a] [r] de manera similar al mínimo tal b. Mostraremos que DP [a] [k] = DP '[a] [r] + rk si y solo si MINB [a] [r] <= k <= MAXB [a] [r]. Además, mostraremos que para cualquier k existe una r para la cual se cumple esta desigualdad.
Tenga en cuenta que MINB [a] [r]> = MINB [a] [r '] y MAXB [a] [r]> = MAXB [a] [r'] si r <r ', por lo tanto, si asumimos que los dos reclamados resultados, podemos hacer una búsqueda binaria para la r, probando los valores O (log n). Por lo tanto, alcanzamos la complejidad O (n log² n) si podemos calcular DP ', MINB y MAXB en el tiempo O (n log n).
Para hacer esto, necesitaremos un árbol de segmentos que almacene las tuplas P [i] = (v_i, low_i, high_i) y admita las siguientes operaciones:
Dado un rango [a, b], encuentre el valor máximo en ese rango (máximo v_i, a <= i <= b), y el mínimo bajo y máximo alto emparejado con ese valor en el rango.
Establecer el valor de la tupla P [i]
Esto es fácil de implementar con un tiempo de complejidad O (log n) por operación, suponiendo cierta familiaridad con los árboles de segmentos. Puede consultar la implementación del algoritmo a continuación para obtener más detalles.
Ahora mostraremos cómo calcular DP ', MINB y MAXB en O (n log n). Fix r. Cree el árbol de segmentos que inicialmente contiene n + 1 valores nulos (-INF, INF, -INF). Mantenemos que P [V [j]] = (DP '[j], MINB [j], MAXB [j]) para j menos que la posición actual i. Ajuste DP '[0] = 0, MINB [0] = 0 y MAXB [0] a 0 si r> 0, de lo contrario a INF y P [0] = (DP' [0], MINB [0], MAXB [ 0]).
Lazo i de 1 a n. Hay dos tipos de subsecuencias que terminan en i: aquellas en las que el elemento anterior es mayor que V [i] y aquellas en las que es menor que V [i]. Para tener en cuenta el segundo tipo, consulte el árbol de segmentos en el rango [0, V [i]]. Deje que el resultado sea (v_1, low_1, high_1). Off1 = (v_1 + 1, low_1, high_1). Para el primer tipo, consulte el árbol de segmentos en el rango [V [i], n]. Deje que el resultado sea (v_2, low_2, high_2). Set off2 = (v_2 + 1 - r, low_2 + 1, high_2 + 1), donde incurrimos en la penalización de r por crear una excepción.
Luego combinamos off1 y off2 en off. Si off1.v> off2.v set off = off1, y si off2.v> off1.v set off = off2. De lo contrario, configure off = (off1.v, min (off1.low, off2.low), max (off1.high, off2.high)). Luego configure DP '[i] = off.v, MINB [i] = off.low, MAXB [i] = off.high y P [i] = off.
Como hacemos consultas de árbol de dos segmentos en cada i, esto toma O (n log n) en total. Es fácil demostrar por inducción que calculamos los valores correctos DP ', MINB y MAXB.
En resumen, el algoritmo es:
Preprocesar, modificando valores para que formen una permutación, y el último valor es el valor más grande.
Búsqueda binaria para la r correcta, con límites iniciales 0 <= r <= n
Inicialice el árbol de segmentos con valores nulos, establezca DP '[0], MINB [0] y MAXB [0].
Bucle de i = 1 a n, en el paso i
Si MINB [n] [r] <= k <= MAXB [n] [r], devuelve DP '[n] [r] + kr - 1.
De lo contrario, si MAXB [n] [r] <k, la r correcta es menor que la r actual. Si MINB [n] [r]> k, la r correcta es mayor que la r actual. Actualice los límites en r y regrese al paso 1.
Aquí hay una implementación de C ++ para este algoritmo. También encuentra la subsecuencia óptima.
Ahora probaremos las dos afirmaciones. Queremos demostrar que
DP '[a] [r] = DP [a] [b] - rb si y solo si MINB [a] [r] <= b <= MAXB [a] [r]
Para todo a, k existe un número entero r, 0 <= r <= n, tal que MINB [a] [r] <= k <= MAXB [a] [r]
Ambos se derivan de la concavidad del problema. Concavidad significa que DP [a] [k + 2] - DP [a] [k + 1] <= DP [a] [k + 1] - DP [a] [k] para todo a, k. Esto es intuitivo: cuantas más excepciones se nos permita hacer, menos nos permitirá que uno más nos ayude.
Arregle ay r. Establezca f (b) = DP [a] [b] - rb, y d (b) = f (b + 1) - f (b). Tenemos d (k + 1) <= d (k) de la concavidad del problema. Suponga que x <y y f (x) = f (y)> = f (i) para todo i. Por lo tanto, d (x) <= 0, entonces d (i) <= 0 para i en [x, y). Pero f (y) = f (x) + d (x) + d (x + 1) + ... + d (y - 1), por lo tanto d (i) = 0 para i en [x, y). Por lo tanto, f (y) = f (x) = f (i) para i en [x, y]. Esto prueba el primer reclamo.
Para probar el segundo, establezca r = DP [a] [k + 1] - DP [a] [k] y defina f, d como anteriormente. Entonces d (k) = 0, por lo tanto d (i)> = 0 para i <k y d (i) <= 0 para i> k, por lo tanto, f (k) es máximo según se desee.
Probar la concavidad es más difícil. Para una prueba, vea mi respuesta en cs.stackexchange.
fuente