Zuma
Solución
Explicación
En el espíritu de la DP de rangos, definimos como el número mínimo de deslizamientos necesarios para borrar todas las gemas entre los índices y inclusive. Si entonces no hay gemas en el rango y el arreglo devolverá .
Hay dos situaciones desde las que podemos transicionar.
La primera es más simple: borramos el primer elemento o los dos primeros del arreglo (si son iguales). En este caso, el valor que obtenemos es o .
El segundo caso es un poco más feo, y al principio puede parecer poco intuitivo:
Si y las gemas en las posiciones y son del mismo color, entonces podemos actualizar con el siguiente valor candidato:
Uno puede preguntarse por qué no hay un deslizamiento extra en esta transición. Después de todo, ¿dónde borramos las gemas y ?
La respuesta es que podemos borrarlas junto con el último deslizamiento que eliminó lo que quedaba en . Como el último deslizamiento que borró estas gemas era un palíndromo, podemos añadir y al inicio y al final sin problemas.
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<int> gems(n);
for (int i = 0; i < n; ++i) cin >> gems[i];
/*
* this[i][j] = mín. deslizamientos para borrar literalmente todo de i a j (inclusive)
* el +1 es solo un buffer para algunos accesos a rangos inválidos
* (el arreglo siempre devuelve 0 para rangos inválidos)
*/
vector<vector<int>> swipes(n + 1, vector<int>(n, 0));
for (int i = 0; i < n; ++i) swipes[i][i] = 1;
for (int len = 2; len <= n; ++len) {
for (int start = 0; start <= n - len; ++start) {
int end = start + len - 1;
// tal vez solo hay que borrar un extremo por su cuenta
swipes[start][end] = 1 + swipes[start + 1][end];
for (int match = start + 2; match <= end; ++match) {
if (gems[start] == gems[match]) {
// en este caso el último deslizamiento del rango izquierdo también
// puede borrar las gemas en start y match
swipes[start][end] =
min(swipes[start][end],
swipes[start + 1][match - 1] + swipes[match + 1][end]);
}
}
// caso borde para empezar un palíndromo nuevo
if (gems[start] == gems[start + 1]) {
swipes[start][end] =
min(swipes[start][end], swipes[start + 2][end] + 1);
}
}
}
cout << swipes[0][n - 1] << '\n';
return 0;
}import java.io.*;
import java.util.Arrays;
public class Zuma {
public static void main(String[] args) throws IOException {
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
int gemNum = Integer.parseInt(read.readLine());
int[] gems = Arrays.stream(read.readLine().split(" "))
.mapToInt(Integer::parseInt)
.toArray();
/*
* this[i][j] = mín. deslizamientos para borrar literalmente todo de i a j (inclusive)
* el +1 es solo un buffer para algunos accesos a rangos inválidos
* (el arreglo siempre devuelve 0 para rangos inválidos)
*/
int[][] swipes = new int[gemNum + 1][gemNum];
for (int i = 0; i < gemNum; i++) { swipes[i][i] = 1; }
for (int len = 2; len <= gemNum; len++) {
for (int start = 0; start <= gemNum - len; start++) {
int end = start + len - 1;
// tal vez solo hay que borrar un extremo por su cuenta
swipes[start][end] = 1 + swipes[start + 1][end];
for (int match = start + 2; match <= end; match++) {
if (gems[start] == gems[match]) {
// en este caso el último deslizamiento del rango izquierdo también
// puede borrar las gemas en start y match
swipes[start][end] =
Math.min(swipes[start][end], swipes[start + 1][match - 1] +
swipes[match + 1][end]);
}
}
// caso borde para empezar un palíndromo nuevo
if (gems[start] == gems[start + 1]) {
swipes[start][end] =
Math.min(swipes[start][end], swipes[start + 2][end] + 1);
}
}
}
System.out.println(swipes[0][gemNum - 1]);
}
}