Introducción a los algoritmos voraces
| Fuente | Recurso | Notas |
|---|---|---|
| CPH | 6.1 - Coin Problem | los otros ejemplos están fuera del alcance de Bronce |
De lo anterior:
Un algoritmo voraz (greedy) construye una solución al problema eligiendo siempre una opción que parece la mejor en ese momento. Un algoritmo voraz nunca deshace sus elecciones, sino que construye de forma directa la solución final. Por eso, los algoritmos voraces suelen ser muy eficientes.
Voraz no se refiere a un único algoritmo, sino a una forma de pensar que se aplica a los problemas; no hay una sola manera de hacer algoritmos voraces. Por eso, usamos una selección de ejemplos conocidos para ayudar a entender el paradigma voraz.
| Hecho | Fuente | Nombre | Dificultad | Tags | Solución |
|---|---|---|---|---|---|
| Bronze | Mad Scientist | Fácil | Greedy | en el módulo |
Solución - Mad Scientist
Solución
En este problema, la solución voraz correcta es ir invirtiendo de forma continua los rangos más largos posibles de vacas que no coinciden.
Mad Scientist tiene un editorial excelente, con una solución en video y una demostración intuitiva.
Se recomienda mucho leerlo para entender mejor el algoritmo voraz.
Implementación
Complejidad temporal:
#include <fstream>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
int main() {
int cow_num;
std::ifstream read("breedflip.in");
read >> cow_num;
vector<char> a(cow_num);
for (char &c : a) { read >> c; }
vector<char> b(cow_num);
for (char &c : b) { read >> c; }
// diff[i] es true si las vacas difieren en la i-ésima posición
// nótese que hay un false extra al principio
vector<bool> diff(cow_num + 1);
for (int i = 0; i < cow_num; i++) { diff[i + 1] = a[i] != b[i]; }
/*
* contar cuántas veces aparece [false, true] en diff
* esto equivale a la cantidad de segmentos continuos de trues
* ese false extra al principio resulta útil acá,
* porque si no lo tuviéramos habría que tratar como caso borde
* el primer segmento que no tiene un false precedente
*/
int min_flips = 0;
for (int i = 0; i < cow_num; i++) {
if (!diff[i] && diff[i + 1]) { min_flips++; }
}
std::ofstream("breedflip.out") << min_flips << endl;
}import java.io.*;
import java.util.*;
public class BreedFlip {
public static void main(String[] args) throws IOException {
BufferedReader read = new BufferedReader(new FileReader("breedflip.in"));
int cowNum = Integer.parseInt(read.readLine());
String a = read.readLine();
String b = read.readLine();
// diff[i] es true si las vacas difieren en la i-ésima posición
// nótese que hay un false extra al principio
boolean[] diff = new boolean[cowNum + 1];
for (int i = 0; i < cowNum; i++) { diff[i + 1] = a.charAt(i) != b.charAt(i); }
/*
* contar cuántas veces aparece [false, true] en diff
* esto equivale a la cantidad de segmentos continuos de trues
* ese false extra al principio resulta útil acá,
* porque si no lo tuviéramos habría que tratar como caso borde
* el primer segmento que no tiene un false precedente
*/
int minFlips = 0;
for (int i = 0; i < cowNum; i++) {
if (!diff[i] && diff[i + 1]) { minFlips++; }
}
PrintWriter written = new PrintWriter(new FileWriter("breedflip.out"));
written.println(minFlips);
written.close();
}
}with open("breedflip.in") as f:
cow_num = int(f.readline())
a = f.readline().strip()
b = f.readline().strip()
# diff[i] es true si las vacas difieren en la i-ésima posición
# nótese que hay un false extra al principio
diff = [False for _ in range(cow_num + 1)]
for i in range(cow_num):
diff[i + 1] = a[i] != b[i]
"""
contar cuántas veces aparece [false, true] en diff
esto equivale a la cantidad de segmentos continuos de trues
ese false extra al principio resulta útil acá,
porque si no lo tuviéramos habría que tratar como caso borde
el primer segmento que no tiene un false precedente
"""
min_flips = 0
for i in range(cow_num):
if not diff[i] and diff[i + 1]:
min_flips += 1
print(min_flips, file=open("breedflip.out", "w"))Nota: a menudo no es obvio si un algoritmo voraz es correcto o no. Si es la solución prevista, se espera que quienes escribieron el problema puedan demostrar su corrección. Sin embargo, como competidor, si el algoritmo es fácil de implementar, una opción es simplemente codearlo y ver si pasa. Quienes hacen programación competitiva llaman a esto “Proof by AC”, o “demostración por Accepted”.
Problemas
| Hecho | Fuente | Nombre | Dificultad | Tags | Solución |
|---|---|---|---|---|---|
| Bronze | Watching Mooloo | Fácil | Greedy | Solución | |
| Bronze | Cow Tipping | Normal | Greedy | Solución | |
| Bronze | Even More Odd Photos | Normal | Greedy | Solución | |
| Bronze | ★ Out of Place | Normal | Greedy | Solución | |
| Bronze | Astral Superposition | Normal | Greedy | Solución | |
| Bronze | Purchasing Milk | Normal | Greedy | Solución | |
| Bronze | Milking Order | Difícil | Greedy | Solución | |
| Bronze | ★ Photoshoot | Difícil | Greedy | Solución | |
| Bronze | FEB | Muy difícil | Casework, Greedy | Solución | |
| Bronze | ★ Race | Muy difícil | Greedy | Solución |
Quiz
Pregunta 1/3