Medio · voraz

Tiempo mínimo de espera

El primero no hace esperar a nadie; el último hace esperar a todos. Cada minuto del llenado de alguien lo pagan los que van detrás — así que la cola más barata pone los tiempos pequeños donde se multiplican menos.

En una fraseOrdena en ascendente y acumula: la persona i espera la suma de todos los anteriores. Tras ordenar, <code>total += wait; wait += a[i]</code> es toda la solución.

El problema

Entrada: La primera línea es n (1 ≤ n ≤ 100). La segunda trae n enteros (1 ≤ a ≤ 1000): los segundos que tarda cada persona en llenar.

Salida: El tiempo total de espera mínimo posible, donde el tiempo de espera de alguien es todo lo anterior a que empiece su llenado (su propio llenado no cuenta).

Ejemplos:

EntradaSalida
4
3 1 4 1
8
1
5
0

En el ejemplo, el mejor orden es 1, 1, 3, 4: esperan 0, 1, 2 y 5 — total 8. Cualquier otro orden paga más; se puede demostrar que el ordenado es el mínimo.

Tu solución

main.cpp — tu solución
Entrada personalizada para «Ejecutar mi entrada»

La corrección corre en tu navegador contra pruebas ocultas. Un bucle infinito se corta a los 3 segundos — aun así, asegúrate de que todo bucle tenga salida. Tu código se guarda solo mientras escribes.

¿Atascado? Pistas

Pista 1 — Escribe lo que cambia un intercambio

Toma dos vecinos x delante de y e imagina intercambiarlos. Solo cambian sus dos esperas: con x delante pagan y; con y delante pagan x. Intercambiar conviene justo cuando y < x — así que en una cola óptima toda pareja vecina es ascendente, lo que fuerza a la cola entera a estar ordenada. Ese es el argumento de intercambio, y es como demuestras un voraz en vez de esperar que funcione.

Pista 2 — El barrido es un prefijo corriente

Tras ordenar, la persona i espera la suma de a[0..i-1]. En vez de un bucle interno, lleva wait: por cada persona, total += wait; y después wait += a[i];. Dos sumas por persona, sin segundo bucle — la misma idea de prefijo que Sumas por rangos.

Pista 3 — La espera va antes, no después

El enunciado dice que el propio llenado no cuenta como espera. El barrido con prefijo lo hace bien de serie — pero si incluyes a[i] en el prefijo, toda respuesta sale agrandada en Σa[i], y el bug se esconde dentro de un número que parece plausible.

Solución (¡inténtalo primero!)
#include <iostream>
using namespace std;

int a[105];

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];

    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            if (a[j] > a[j + 1]) {
                int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
            }
        }
    }

    long long total = 0, wait = 0;
    for (int i = 0; i < n; i++) {
        total += wait;
        wait += a[i];
    }
    cout << total << endl;
    return 0;
}

Este es el principio de primero-el-trabajo-más-corto de los sistemas operativos, demostrado con cuatro líneas de argumento de intercambio. Su hermano ya lo conociste: Monedas mínimas era voraz con otra prueba, y Ordenamiento burbuja es la maquinaria que ambos reutilizan. Cuando un voraz te parezca correcto, el ejercicio es siempre el mismo: encuentra el intercambio que mejoraría cualquier respuesta no ordenada.

Análisis profundo

Por qué funciona

Argumento de intercambio: toma cualquier cola que no esté ordenada en ascendente e intercambia una pareja vecina desordenada (x delante de y con y < x). Solo cambian las esperas de esos dos, y bajan en x − y. Así que una cola desordenada siempre puede mejorarse, y el único óptimo local es el ordenado — eso es una demostración, no una esperanza.

El coste

O(n²) para la burbuja y O(n) para el barrido; con n ≤ 100 son unas 10.000 comparaciones. La espera total cabe de sobra en 64 bits (100 personas × 1000 s ≈ 5 millones de segundos).

Dónde falla

  • Contar el propio llenado de cada persona como espera infla todas las respuestas en Σa[i] — el barrido debe hacer total += wait ANTES de ampliar wait con a[i].
  • Ordenar una copia y barrer el array original (o al revés) — la respuesta en silencio no corresponde a ningún orden.
  • Olvidar que los tiempos iguales pueden ir en cualquier orden entre sí: los empates son gratis, no compliques el orden por ellos.

Siguiente paso

La hermana voraz con otra prueba es Monedas mínimas — lee los dos argumentos de intercambio juntos. El ordenamiento que ambos reutilizan es Ordenamiento burbuja.

Dos cosas para recordar

  • Primero los rápidos: cada minuto del que va delante lo pagan todos los de detrás.
  • Argumento de intercambio = la plantilla de prueba del voraz: encuentra el intercambio que mejoraría cualquier respuesta desordenada.
🐞 Esta versión falla: ábrela y pruébala

Barre en orden de llegada: la cola nunca se ordenó

#include <iostream>
using namespace std;

int a[105];

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];
    long long total = 0, wait = 0;
    for (int i = 0; i < n; i++) {   // bug: no sorting first
        total += wait;
        wait += a[i];
    }
    cout << total << endl;
    return 0;
}