Skip to Content

Stick Divisions

Solución en video

Por Abhiraj Mallangi

Nota: la solución en video puede no coincidir con las demás soluciones. Código en Java.

Video de YouTube (-v1Kn629m3E)

Solución

Explicación

En este problema nos piden hallar el costo mínimo para dividir un palo de longitud xx en nn palos de longitudes dadas. Ayuda pensar al revés: ¿qué pasa si partimos de palos de longitudes d1,,dnd_1,\ldots,d_n y los fusionamos en uno?

Resulta que esto se puede resolver usando Huffman Coding (véase también Wikipedia ). El algoritmo es simple: tomar los dos palos más cortos, fusionarlos en uno y repetir.

Si te preguntas por qué Huffman Coding siempre produce una solución óptima, véase aquí .

Como queremos seleccionar los dos palos más cortos y luego insertar el palo combinado nuevo, necesitamos una estructura de datos en la que podamos obtener el valor más pequeño de la colección, quitarlo y añadir valores nuevos. Las operaciones de inserción y eliminación se pueden hacer fácilmente con una cola de prioridad en O(logn)\mathcal{O}(\log n), mientras que recuperar el valor más pequeño toma tiempo constante.

Implementación

Complejidad temporal: O(NlogN)\mathcal{O}(N \log N)

#include <iostream> #include <queue> using namespace std; int main() { ios_base::sync_with_stdio(0); cin.tie(0); int x, n; cin >> x >> n; priority_queue<int, vector<int>, greater<int>> PQ; for (int i = 0; i < n; i++) { int a; cin >> a; PQ.push(a); } long long ans = 0; for (int i = 1; i < n; i++) { int a = PQ.top(); PQ.pop(); int b = PQ.top(); PQ.pop(); PQ.push(a + b); ans += a + b; } cout << ans << "\n"; return 0; }
import java.io.*; import java.util.*; public class StickDivision { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(in.readLine()); // with our algorithm the variable x will not be used at all int x = Integer.parseInt(st.nextToken()); int n = Integer.parseInt(st.nextToken()); Queue<Integer> sticks = new PriorityQueue<Integer>(); st = new StringTokenizer(in.readLine()); for (int i = 0; i < n; i++) sticks.add(Integer.valueOf(st.nextToken())); long costs = 0; // we keep combining two smallest sticks a and b // until there is only one stick remaining, which will have the length x while (sticks.size() > 1) { int a = sticks.remove(); int b = sticks.remove(); sticks.add(a + b); // the length of the combined stick is the cost for dividing them // into the separated sticks a and b costs += a + b; } System.out.println(costs); } }
import heapq x, n = map(int, input().split()) d = list(map(int, input().split())) heapq.heapify(d) res = 0 for _ in range(n - 1): a = heapq.heappop(d) b = heapq.heappop(d) res += a + b heapq.heappush(d, a + b) print(res)