Está en la página 1de 100

Traducido del inglés al español - www.onlinedoctranslator.

com
Contenido

Prefacio vi

Prefacio viii

Perfiles de los autores xix

lista de abreviaciones XX

Lista de tablas xxx

Lista de Figuras XXII

1 Introducción 1
1.1 Programación Competitiva. . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Consejos para ser Competitivo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1 Sugerencia 1: ¡Escriba el código más rápido! . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.2 Sugerencia 2: Identifique rápidamente los tipos de problemas . . . . . . . . . . . . . . . . . 4
1.2.3 Sugerencia 3: Realice un análisis de algoritmos. . . . . . . . . . . . . . . . . . . . . . 6
1.2.4 Consejo 4: Lenguajes de programación maestros . . . . . . . . . . . . . . . . . 10
1.2.5 Sugerencia 5: Domine el arte de probar el código . . . . . . . . . . . . . . . . . 13
1.2.6 Consejo 6: Práctica y más práctica . . . . . . . . . . . . . . . . . . . 15
1.2.7 Consejo 7: Trabajo en equipo (para ICPC) . . . . . . . . . . . . . . . . . . . . . . dieciséis

1.3 Primeros pasos: los problemas fáciles . . . . . . . . . . . . . . . . . . . . . . dieciséis

1.3.1 Anatomía de un problema de concurso de programación. . . . . . . . . . . . . dieciséis

1.3.2 Rutinas típicas de entrada/salida. . . . . . . . . . . . . . . . . . . . . 17


1.3.3 Hora de iniciar el viaje. . . . . . . . . . . . . . . . . . . . . . . . 19
1.4 Los problemas ad hoc. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.5 Soluciones a ejercicios sin estrella . . . . . . . . . . . . . . . . . . . . . . . 27
1.6 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

2 Estructuras de datos y bibliotecas 33


2.1 Resumen y motivación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2 DS lineal con bibliotecas integradas. . . . . . . . . . . . . . . . . . . . . . . . 35
2.3 DS no lineal con bibliotecas integradas. . . . . . . . . . . . . . . . . . . . . 43
2.4 Estructuras de datos con librerías propias. . . . . . . . . . . . . . . . . . . . 49
2.4.1 Gráfico. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.4.2 Unión-búsqueda de conjuntos disjuntos. . . . . . . . . . . . . . . . . . . . . . . . . 52
2.4.3 Árbol de segmentos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.4.4 Árbol indexado binario (Fenwick) . . . . . . . . . . . . . . . . . . . . . 59
2.5 Solución de ejercicios sin asterisco. . . . . . . . . . . . . . . . . . . . . . . . 64
2.6 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

i
CONTENIDO ©
c Steven y Félix

3 Paradigmas de resolución de problemas 69


3.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.2 Búsqueda completa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.2.1 Búsqueda completa iterativa. . . . . . . . . . . . . . . . . . . . . . . . 71
3.2.2 Búsqueda completa recursiva. . . . . . . . . . . . . . . . . . . . . . . . 74
3.2.3 Consejos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.3 Divide y vencerás. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.3.1 Usos interesantes de la búsqueda binaria. . . . . . . . . . . . . . . . . . . 84
3.4 Codicioso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.4.1 Ejemplos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.5 Programación Dinámica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.5.1 Ilustración de PD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.5.2 Ejemplos clásicos. . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.5.3 Ejemplos no clásicos. . . . . . . . . . . . . . . . . . . . . . . . . 112
3.6 Solución de Ejercicios No Destacados . . . . . . . . . . . . . . . . . . . . . . . . 118
3.7 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120

4 Grafico 121
4.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
4.2 Gráfico transversal. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
4.2.1 Primera búsqueda en profundidad (DFS) . . . . . . . . . . . . . . . . . . . . . . . . 122
4.2.2 Búsqueda primero en amplitud (BFS) . . . . . . . . . . . . . . . . . . . . . . . 123
4.2.3 Encontrar componentes conectados (gráfico no dirigido) . . . . . . . . . 125
4.2.4 Relleno por inundación: etiquetado/coloreado de los componentes conectados. . . . . . 125
4.2.5 Clasificación topológica (Gráfico acíclico dirigido) . . . . . . . . . . . . . . . 126
4.2.6 Comprobación de gráfico bipartito. . . . . . . . . . . . . . . . . . . . . . . . . . 128
4.2.7 Comprobación de la propiedad de los bordes del gráfico a través del árbol de expansión DFS. . . . . . . . . 128
4.2.8 Búsqueda de puntos de articulación y puentes (gráfico no dirigido) . . . . . 130
4.2.9 Encontrar componentes fuertemente conectados (Gráfico dirigido) . . . . . . 133
4.3 Árbol de expansión mínimo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
4.3.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . 138
4.3.2 Algoritmo de Kruskal. . . . . . . . . . . . . . . . . . . . . . . . . . . 138
4.3.3 Algoritmo de Prim. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
4.3.4 Otras aplicaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
4.4 Rutas más cortas de fuente única. . . . . . . . . . . . . . . . . . . . . . . . . . . 146
4.4.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . 146
4.4.2 SSSP en gráfico no ponderado. . . . . . . . . . . . . . . . . . . . . . . 146
4.4.3 SSSP en gráfico ponderado. . . . . . . . . . . . . . . . . . . . . . . . 148
4.4.4 SSSP en gráfico con ciclo de peso negativo. . . . . . . . . . . . . . 151
4.5 Rutas más cortas de todos los pares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
4.5.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . 155
4.5.2 Explicación de la solución DP de Floyd Warshall. . . . . . . . . . . . . 156
4.5.3 Otras aplicaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
4.6 Flujo de red. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
4.6.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . 163
4.6.2 Método de Ford Fulkerson. . . . . . . . . . . . . . . . . . . . . . . . . 163
4.6.3 Algoritmo de Edmonds Karp. . . . . . . . . . . . . . . . . . . . . . . 164
4.6.4 Modelado de gráfico de flujo - Parte 1 . . . . . . . . . . . . . . . . . . . . . . 166
4.6.5 Otras aplicaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
4.6.6 Modelado de gráfico de flujo - Parte 2 . . . . . . . . . . . . . . . . . . . . . . 168

yo
CONTENIDO ©
c Steven y Félix

4.7 Gráficos especiales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171


4.7.1 Gráfico acíclico dirigido. . . . . . . . . . . . . . . . . . . . . . . . . . 171
4.7.2 Árbol. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
4.7.3 Gráfico Euleriano. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
4.7.4 Gráfico bipartito. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
4.8 Solución de ejercicios sin asterisco. . . . . . . . . . . . . . . . . . . . . . . . 187
4.9 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190

5 Matemáticas 191
5.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
5.2 Problemas matemáticos ad hoc. . . . . . . . . . . . . . . . . . . . . . . . . 192
5.3 Clase BigInteger de Java. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
5.3.1 Funciones básicas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
5.3.2 Funciones de bonificación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
5.4 Combinatoria. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
5.4.1 Números de Fibonacci. . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
5.4.2 Coeficientes binomiales. . . . . . . . . . . . . . . . . . . . . . . . . . . 205
5.4.3 Números catalanes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
5.4.4 Comentarios sobre Combinatoria en Concursos de Programación. . . . . . . 206
5.5 Teoría de números. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
5.5.1 Números primos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
5.5.2 Máximo común divisor y mínimo común múltiplo. . . . . . . . . 211
5.5.3 Factoriales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
5.5.4 Búsqueda de factores primos con divisiones de prueba optimizadas. . . . . . . . . 212
5.5.5 Trabajar con factores primos. . . . . . . . . . . . . . . . . . . . . . . 213
5.5.6 Funciones que involucran factores primos. . . . . . . . . . . . . . . . . . . 214
5.5.7 Tamiz modificado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
5.5.8 Módulo aritmético. . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
5.5.9 Euclides ampliado: resolución de la ecuación diofántica lineal . . . . . . . . 217
5.5.10 Comentarios sobre Teoría de Números en Concursos de Programación. . . . . . 217
5.6 Teoría de la probabilidad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
5.7 Búsqueda de ciclos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
5.7.1 Solución(es) utilizando una estructura de datos eficiente. . . . . . . . . . . . . . . 223
5.7.2 Algoritmo de búsqueda de ciclos de Floyd. . . . . . . . . . . . . . . . . . . . 223
5.8 Teoría de juegos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
5.8.1 Árbol de decisión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
5.8.2 Conocimientos matemáticos para acelerar la solución. . . . . . . . . . . . 227
5.8.3 Juego Nim. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
5.9 Solución de ejercicios sin asterisco. . . . . . . . . . . . . . . . . . . . . . . . 229
5.10 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231

6 Procesamiento de cadenas 233


6.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
6.2 Habilidades básicas de procesamiento de cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . 234
6.3 Problemas de procesamiento de cadenas ad hoc. . . . . . . . . . . . . . . . . . . . . . . 236
6.4 Coincidencia de cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
6.4.1 Soluciones de biblioteca. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
6.4.2 Algoritmo de Knuth-Morris-Pratt (KMP) . . . . . . . . . . . . . . . . 241
6.4.3 Coincidencia de cadenas en una cuadrícula 2D. . . . . . . . . . . . . . . . . . . . . . 244
6.5 Procesamiento de cadenas con programación dinámica. . . . . . . . . . . . . . . . . 245

iii
CONTENIDO ©
c Steven y Félix

6.5.1 Alineación de cadenas (Editar distancia) . . . . . . . . . . . . . . . . . . . . 245


6.5.2 Subsecuencia común más larga. . . . . . . . . . . . . . . . . . . . . . 247
6.5.3 Procesamiento de cadenas no clásico con DP. . . . . . . . . . . . . . . . 247
6.6 Sufijo Trie/Tree/Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
6.6.1 Sufijo Trie y Aplicaciones. . . . . . . . . . . . . . . . . . . . . . . 249
6.6.2 Árbol de sufijos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
6.6.3 Aplicaciones del árbol de sufijos. . . . . . . . . . . . . . . . . . . . . . . . 251
6.6.4 Matriz de sufijos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
6.6.5 Aplicaciones de la matriz de sufijos. . . . . . . . . . . . . . . . . . . . . . . 258
6.7 Solución de ejercicios sin estrella. . . . . . . . . . . . . . . . . . . . . . . . 264
6.8 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267

7 (Geometría Computacional 269


7.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
7.2 Objetos de geometría básica con bibliotecas. . . . . . . . . . . . . . . . . . . . . 271
7.2.1 Objetos 0D: Puntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
7.2.2 Objetos 1D: Líneas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
7.2.3 Objetos 2D: Círculos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
7.2.4 Objetos 2D: Triángulos . . . . . . . . . . . . . . . . . . . . . . . . . . 278
7.2.5 Objetos 2D: Cuadriláteros . . . . . . . . . . . . . . . . . . . . . . . . 281
7.3 Algoritmo sobre Polígono con Bibliotecas. . . . . . . . . . . . . . . . . . . . . . 285
7.3.1 Representación de polígonos. . . . . . . . . . . . . . . . . . . . . . . . . 285
7.3.2 Perímetro de un Polígono. . . . . . . . . . . . . . . . . . . . . . . . . . 285
7.3.3 Área de un polígono. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
7.3.4 Comprobar si un polígono es convexo. . . . . . . . . . . . . . . . . . . . . 286
7.3.5 Comprobar si un punto está dentro de un polígono. . . . . . . . . . . . . . . . . 287
7.3.6 Cortar un polígono con una línea recta. . . . . . . . . . . . . . . . . . 288
7.3.7 Hallar la envolvente convexa de un conjunto de puntos. . . . . . . . . . . . . . . 289
7.4 Solución de ejercicios sin estrella. . . . . . . . . . . . . . . . . . . . . . . . 294
7.5 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297

8 Temas más avanzados 299


8.1 Descripción general y motivación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
8.2 Técnicas de búsqueda más avanzadas ....................... 299
8.2.1 Retroceder con máscara de bits ....................... 299
8.2.2 Retroceso con poda intensa. . . . . . . . . . . . . . . . . . . . 304
8.2.3 Búsqueda en el espacio de estados con BFS o Dijkstra. . . . . . . . . . . . . . . 305
8.2.4 Meet in the Middle (búsqueda bidireccional) . . . . . . . . . . . . . . . 306
8.2.5 Búsqueda informada: A* e IDA* . . . . . . . . . . . . . . . . . . . . . 308
8.3 Técnicas de DP más avanzadas. . . . . . . . . . . . . . . . . . . . . . . . . 312
8.3.1 DP con máscara de bits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
8.3.2 Compilación de parámetros comunes (DP) . . . . . . . . . . . . . . . 313
8.3.3 Manejo de valores de parámetros negativos con la técnica de compensación. . . . . . 313
8.3.4 MLE? Considere usar BST balanceado como tabla de notas. . . . . . . . . 315
8.3.5 MLE/TLE? Utilice una mejor representación estatal. . . . . . . . . . . . . . 315
8.3.6 MLE/TLE? Suelta un parámetro, recupéralo de otros. . . . . . 316
8.4 Descomposición del problema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
8.4.1 Dos componentes: búsqueda binaria de la respuesta y otros . . . . . . . 320
8.4.2 Dos componentes: con RSQ/RMQ estático 1D . . . . . . . . . . 322
8.4.3 Dos componentes: preprocesamiento de gráficos y DP . . . . . . . . . . . . 322

IV
CONTENIDO ©
c Steven y Félix

8.4.4 Dos Componentes: Gráfica Involucrante . . . . . . . . . . . . . . . . . . . 324


8.4.5 Dos Componentes: Matemáticas Involucradas . . . . . . . . . . . . . . . 324
8.4.6 Dos componentes: búsqueda completa y geometría . . . . . . . . . . 324
8.4.7 Dos componentes: una estructura de datos eficiente. . . . . . . . . 324
8.4.8 Tres componentes. . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
8.5 Solución de ejercicios sin asterisco. . . . . . . . . . . . . . . . . . . . . . . . 332
8.6 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333

9 Temas raros 335


9.1 Problema 2-SAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
9.2 Problema de la galería de arte. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
9.3 Problema del viajante bitónico. . . . . . . . . . . . . . . . . . . . . . 339
9.4 Coincidencia de soportes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
9.5 Problema del cartero chino. . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
9.6 Problema del par más cercano. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
9.7 Algoritmo de Dinic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
9.8 Fórmulas o teoremas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
9.9 Algoritmo de eliminación de Gauss. . . . . . . . . . . . . . . . . . . . . . . . . 346
9.10 Coincidencia de gráficos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
9.11 Distancia de círculo máximo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
9.12 Algoritmo de Hopcroft Karp. . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
9.13 Trayectos independientes y disjuntos por aristas . . . . . . . . . . . . . . . . . . . . . . 354
9.14 Índice de inversión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
9.15 Problema de Josefo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
9.16 Movimientos del caballo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
9.17 Algoritmo de Kosaraju. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
9.18 Antepasado común más bajo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
9.19 Construcción de cuadrados mágicos (tamaño impar) . . . . . . . . . . . . . . . . . . . . . 361
9.20 Multiplicación de cadenas de matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
9.21 Potencia matricial. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
9.22 Conjunto independiente ponderado máx. . . . . . . . . . . . . . . . . . . . . . . . . 368
9.23 Flujo de costo mínimo (máximo) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
9.24 Cobertura de ruta mínima en DAG. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
9.25 Clasificación de panqueques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
9.26 Algoritmo de factorización de enteros rho de Pollard. . . . . . . . . . . . . . . . . . . . 374
9.27 Calculadora y conversión de sufijos . . . . . . . . . . . . . . . . . . . . . . . . 376
9.28 Números romanos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
9.29 Problema de selección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
9.30 Algoritmo más rápido de la ruta más corta . . . . . . . . . . . . . . . . . . . . . . . . . 383
9.31 Ventana corrediza. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
9.32 Clasificación en tiempo lineal. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
9.33 Estructura de datos de tabla dispersa. . . . . . . . . . . . . . . . . . . . . . . . . . . 388
9.34 Torre de Hanoi. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
9.35 Notas del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391

A uCaza 393

B Créditos 396

Bibliografía 398

v
CONTENIDO ©
c Steven y Félix

Prefacio
Hace mucho tiempo (el 11elde noviembre de 2003, martes, 3:55:57 UTC), recibí un correo
electrónico con el siguiente mensaje:

“Debo decir en pocas palabras que con el Sitio UVa, ha dado a luz a una nueva
CIVILIZACIÓN y con los libros que escribe (se refería a “Programming Challenges:
The Programming Contest Training Manual” [60], en coautoría con Steven Skiena) ,
inspiras a los soldados a seguir marchando. Que vivas mucho tiempo para servir a la
humanidad produciendo programadores sobrehumanos”.

Aunque eso era claramente una exageración, me hizo pensar. Tenía un sueño: crear una comunidad
en torno al proyecto que había iniciado como parte de mi trabajo docente en la UVa, con personas de
todo el mundo trabajando juntas por un mismo ideal. Con un poco de búsqueda, encontré
rápidamente toda una comunidad en línea que ejecuta un anillo web de sitios con excelentes
herramientas que cubren y brindan todo lo que le faltaba al sitio UVa.
Para mí, 'Methods to Solve' de Steven Halim, un estudiante muy joven de Indonesia, fue uno de
los sitios web más impresionantes. Me inspiré a creer que el sueño se haría realidad algún día, porque
en este sitio web yacía el resultado del arduo trabajo de un genio de los algoritmos y la informática.
Además, sus objetivos declarados coincidían con el núcleo de mi sueño: servir a la humanidad. Aún
mejor, tiene un hermano con intereses y capacidades similares, Felix Halim.
Es una pena que se tarde tanto en empezar una colaboración real, pero la vida es así.
Afortunadamente, todos hemos seguido trabajando juntos de manera paralela hacia la
realización de ese sueño, el libro que ahora tienes en tus manos es prueba de ello.
No imagino mejor complemento para el Juez Online de la UVa. Este libro utiliza muchos ejemplos de
UVa cuidadosamente seleccionados y categorizados tanto por tipo de problema como por técnica de
resolución, proporcionando una ayuda increíblemente útil para los usuarios del sitio. Al dominar y practicar
la mayoría de los ejercicios de programación de este libro, un lector puede resolver fácilmente al menos 500
problemas en el Juez en línea de UVa, que los colocará entre los 400 y 500 primeros entre ≈100000 usuarios
UVa DO.
Está claro que el libro “Programación Competitiva: Incrementando el Límite Inferior de los
Concursos de Programación” es adecuado para los programadores que quieren mejorar sus
posiciones en los próximos ICPC regionales e IOI. Los dos autores han pasado por estos
concursos (ICPC e IOI) como concursantes y ahora como entrenadores. Pero también es un
colega esencial para los recién llegados, como dicen Steven y Felix en la introducción, "el libro no
debe leerse una vez, sino varias veces".
Además, contiene código fuente C++ práctico para implementar algoritmos dados. Comprender
un problema es una cosa, pero conocer el algoritmo para resolverlo es otra, e implementar bien la
solución en un código breve y eficiente es complicado. Después de haber leído este extraordinario
libro tres veces, te darás cuenta de que eres mucho mejor programador y, lo que es más importante,
una persona más feliz.

vi
CONTENIDO ©
c Steven y Félix

Miguel A. Revilla, Universidad de Valladolid


Creador del sitio UVa Online Judge;
Miembro del Comité Directivo Internacional de ACM-ICPC y archivista de problemas
http://uva.onlinejudge.org; http://livearchive.onlinejudge.org

viii
CONTENIDO ©
c Steven y Félix

Prefacio
Este libro es imprescindible para todo programador competitivo. Dominar el contenido de
este libro es una condición necesaria (pero tal vez no suficiente) si uno desea dar un salto y
pasar de ser un codificador cualquiera a estar entre los mejores programadores del mundo.

Los lectores típicos de este libro incluirían:

1. Estudiantes universitarios que compiten en el Concurso internacional anual de programación


universitaria (ICPC) de ACM [66] Concursos regionales (incluidas las Finales mundiales),

2. Estudiantes de secundaria o bachillerato que compiten en la Olimpiada Internacional de


Informática (IOI) anual [34] (incluidas las Olimpiadas Nacionales o Provinciales),

3. Entrenadores que buscan materiales de formación integrales para sus alumnos [24],

4. Cualquiera que ame resolver problemas a través de programas de computadora. Hay


numerosos concursos de programación para aquellos que ya no son elegibles para ICPC,
incluidos TopCoder Open, Google CodeJam, Internet Problem Solving Contest (IPSC), etc.

requisitos previos

Este libro esnoescrito para programadores novatos. Este libro está dirigido a lectores que tengan al menos
conocimientos básicos en metodología de programación, estén familiarizados con al menos uno de estos
lenguajes de programación (C/C++ o Java, preferiblemente ambos), hayan aprobado un curso básico de
estructuras de datos y algoritmos (normalmente impartido en primer año del plan de estudios universitario
de Ciencias de la Computación), y comprender el análisis algorítmico simple (al menos la notación O
grande). En la tercera edición, se ha agregado más contenido para que este libro también pueda usarse
como lectura complementariapara un básicoEstructuras de datos y algoritmoscurso.

A los concursantes de ACM ICPC

viii
CONTENIDO ©
c Steven y Félix

Sabemos que uno probablemente no puede ganar el ACM ICPC regional simplemente dominando los
contenidos delversión actual (tercera edición)de este libro Si bien hemos incluido una gran cantidad de
materiales en este libro, mucho más que en las dos primeras ediciones, somos conscientes de que se
requiere mucho más de lo que este libro puede ofrecer para lograr esa hazaña. En las notas de los capítulos
se enumeran algunos indicadores adicionales de referencias útiles para los lectores que desean más.
Creemos, sin embargo, que a su equipo le irá mucho mejor en futuros CIPC después de dominar el
contenido de este libro. Esperamos que este libro le sirva tanto de inspiración como de motivación para su
viaje de 3 a 4 años compitiendo en ACM ICPC durante sus días universitarios.

A los concursantes de IOI

Muchos de nuestros consejos para los concursantes de ACM ICPC también se aplican a usted. Los planes de
estudio de ACM ICPC e IOI son muy similares, excepto que IOI,por ahora, actualmente excluye los temas
enumerados en la siguiente Tabla 1. Puede omitir estos elementos hasta sus años universitarios (cuando se una a
los equipos ACM ICPC de esa universidad). Sin embargo, aprender estas técnicas por adelantado definitivamente
puede ser beneficioso ya que algunas tareas en IOI pueden volverse más fáciles con conocimiento adicional.
Sabemos que uno no puede ganar una medalla en IOI simplemente dominando los contenidos del versión
actual (tercera edición)de este libro Si bien creemos que muchas partes del plan de estudios de IOI se han incluido
en este libro, con la esperanza de permitirle lograr una puntuación respetable en futuros IOI, somos muy
conscientes de que las tareas modernas de IOI requieren habilidades agudas para resolver problemas y una
creatividad tremenda, virtudes que no podemos. posiblemente impartir a través de este libro de texto estático.
Este libro puede brindarle conocimientos, pero el trabajo duro en última instancia lo debe hacer usted. Con la
práctica viene la experiencia, y con la experiencia viene la habilidad. Entonces, ¡sigue practicando!

Tema En este libro


Estructuras de datos: unión-búsqueda de conjuntos disjuntos Sección 2.4.2
Gráfico: búsqueda de SCC, flujo de red, gráficos bipartitos Sección 4.2.1, 4.6.3, 4.7.4
Matemáticas: BigInteger, teoría de la probabilidad, juegos Nim Sección 5.3, 5.6, 5.8
Procesamiento de cadenas: árboles/matrices de sufijos Sección 6.6
Temas más avanzados: A*/IDA* Sección 8.2
Muchos de los temas raros Capítulo 9

Tabla 1: No en el plan de estudios de IOI [20]Aún

ix
CONTENIDO ©
c Steven y Félix

A los profesores y entrenadores

Este libro se utiliza en el curso CS3233 - 'Programación competitiva' de Steven en la Escuela de Informática de la
Universidad Nacional de Singapur. CS3233 se lleva a cabo en 13 semanas de enseñanza utilizando el siguiente plan
de lección (consulte la Tabla 2). Las diapositivas en PDF (solo la versión pública) se encuentran en el sitio web
complementario de este libro. Los compañeros maestros/entrenadores deben sentirse libres de modificar el plan
de la lección para adaptarlo a las necesidades de los estudiantes. Sugerencias o soluciones breves de lassin
estrella Los ejercicios escritos de este libro se encuentran al final de cada capítulo. Algunos de lossembrado de
estrellas Los ejercicios escritos son bastante desafiantes y no tienen pistas ni soluciones. Estos probablemente se
pueden usar como preguntas de examen o problemas de concurso (por supuesto, ¡resuélvalos primero!).
Este libro también se utiliza como lectura complementaria en el curso CS2010 de Steven:
'Estructuras de datos y algoritmos', principalmente para la implementación de varios algoritmos y
ejercicios escritos/de programación.

semana Tema En este libro


01 Introducción Capítulo 1, Sección 2.2, 5.2, 6.2-6.3, 7.2
02 Estructuras de datos y bibliotecas Capítulo 2
03 Complete Search, Divide & Conquer, Greedy Sección 3.2-3.4; 8.2
04 Programación dinámica 1 (Ideas básicas) Sección 3.5; 4.7.1
05 Programación dinámica 2 (Más técnicas) Concurso Sección 5.4; 5,6; 6,5; 8.3
06 de equipo de mitad de semestre Capítulo 1 - 4; partes del cap
- Vacaciones de mitad de semestre 9 (tarea)
07 Gráfico 1 (Flujo de red) Sección 4.6; partes del Capítulo 9
08 Gráfico 2 (Coincidencia) Sección 4.7.4; partes del capitulo 9
09 Matemáticas (Resumen) capitulo 5
10 Procesamiento de cadenas (habilidades básicas, matriz de Capítulo 6
11 sufijos) (computacional) Geometría (bibliotecas) Capítulo 7
12 Temas más avanzados Sección 8.4; partes de Ch 9
13 Concurso final por equipos Capítulo 1-9 y tal vez más
- sin examen final -

Tabla 2: Plan de lección del CS3233 de Steven

ParaEstructuras de datos y algoritmosCursos


El contenido de este libro se ha ampliado en esta edición para que elfiprimeros cuatrocapítulos de este libro
son más accesibles parafiprimer añoEstudiantes de informática. Los temas y ejercicios que consideramos
relativamente difíciles y, por lo tanto, innecesariamente desalentadores para los novatos, se trasladaron al
Capítulo 8, ahora más voluminoso, o al nuevo Capítulo 9. De esta manera, los estudiantes que son nuevos
en Ciencias de la Computación quizás no se sientan demasiado intimidados. cuando examinan los primeros
cuatro capítulos.
El capítulo 2 ha recibido una actualización importante. Anteriormente, la Sección 2.2 era solo una lista informal
de estructuras de datos clásicas y sus bibliotecas. Esta vez, hemos ampliado la redacción y agregado muchos
ejercicios escritos para que este libro también pueda usarse como apoyo a unEstructuras de datospor supuesto,
especialmente en los términos deimplementacióndetalles.
Los cuatro paradigmas de resolución de problemas discutidos en el Capítulo 3 aparecen con frecuencia en
típicos Algoritmoscursos El texto de este capítulo se ha ampliado y editado para ayudar a los nuevos estudiantes
de Ciencias de la Computación.

X
CONTENIDO ©
c Steven y Félix

Partes del Capítulo 4 también se pueden usar como lectura complementaria oimplementaciónguía para
mejorar unMatemáticas discretas[57, 15] o un básicoAlgoritmoscurso. También proporcionamos algunos
conocimientos nuevos sobre la visualización de técnicas de programación dinámica como algoritmos en DAG.
Actualmente, tal discusión es lamentablemente poco común en muchos libros de texto de Ciencias de la
Computación.

A todos los lectores

Debido a su diversidad de cobertura y profundidad de discusión, este libro esnodestinado a ser leído
una vez, pero varias veces. Hay muchos escritos (≈238) y ejercicios de programación (≈1675)
enumerados y distribuidos en casi todas las secciones. Puede omitir estos ejercicios al principio si la
solución es demasiado difícil o requiere mayor conocimiento y técnica, y repasarlos después de
estudiar otros capítulos de este libro. Resolver estos ejercicios fortalecerá su comprensión de los
conceptos que se enseñan en este libro, ya que generalmente involucran aplicaciones, giros o
variantes interesantes del tema que se está discutiendo. Haga un esfuerzo para intentarlos: el tiempo
que dedique a resolver estos problemas definitivamente no se desperdiciará.
Creemos que este libro es y será relevante para muchos estudiantes universitarios y de
secundaria. Los concursos de programación como el ICPC y el IOI han llegado para quedarse, al
menos durante muchos años. Los nuevos estudiantes deben tratar de comprender e interiorizar los
conocimientos básicos presentados en este libro antes de buscar nuevos desafíos. Sin embargo, el
término 'básico' puede ser un poco engañoso; consulte la tabla de contenido para comprender lo que
queremos decir con 'básico'.
Como puede implicar el título de este libro, el propósito de este libro es claro: nuestro objetivo es
mejorar las habilidades de programación de todos y, por lo tanto, aumentar lalímite inferiorde concursos de
programación como el ICPC y el IOI en el futuro. Con más concursantes dominando los contenidos de este
libro, esperamos que el año 2010 (cuando se publicó la primera edición de este libro) sea un punto de
inflexión que marque una mejora acelerada en los estándares de los concursos de programación.
Esperamos ayudar a más equipos a resolver más (≥2) problemas en futuros ICPC y ayudar a más
concursantes a lograr mayores (≥200) puntuaciones en futuros IOI. También esperamos ver a muchos
entrenadores del ICPC y del IOI de todo el mundo (especialmente en el Sudeste Asiático) adoptar este libro
por la ayuda que proporciona para dominar temas de los que los estudiantes no pueden prescindir en
concursos de programación competitivos. Si se logra tal proliferación del conocimiento de "límite inferior"
requerido para la programación competitiva, entonces se habrá cumplido el objetivo principal de este libro
de aumentar el nivel del conocimiento humano, y nosotros, como autores de este libro, estaremos muy
felices. Por supuesto.

Convención
Hay mucho código C/C++ y también algo de código Java (especialmente en la Sección 5.3)
incluidos en este libro. Si aparecen, se escribirán enesta fuente monoespaciada.
Para el código C/C++ de este libro, hemos adoptado el uso frecuente dedefinición de tipoCorreo
electrónico y macros: funciones que los programadores de la competencia suelen utilizar por conveniencia,
brevedad y velocidad de codificación. Sin embargo, no podemos usar técnicas similares para Java ya que no
contiene características similares o análogas. Estos son algunos ejemplos de nuestros atajos de código C/C+
+:

// Suprimir algunos mensajes de advertencia de compilación (solo para usuarios de VC++)


# definir _CRT_SECURE_NO_DEPRECATE

xi
CONTENIDO ©
c Steven y Félix

// Atajos para tipos de datos "comunes" en concursos


typedef long long ll; // comentarios que se mezclan con el código
par typedef<int, int> ii; // están alineados a la derecha así
vector typedef<ii> viii;
typedef vector<int> vi;
# definir INF 1000000000 // 1 billón, más seguro que 2B para Floyd Warshall's

// Configuraciones comunes de conjunto de miembros

//memset(memo, -1, tamaño del memo); // inicializa la tabla de memorización de DP con


-1 //memset(arr, 0, sizeof arr); // para borrar una matriz de enteros

// Hemos abandonado el uso de "REP" y "TRvii" desde la segunda edición // para


reducir la confusión que encuentran los nuevos programadores
Los siguientes accesos directos se utilizan con frecuencia tanto en nuestro código C/C++ como en Java:

// respuesta = un ? antes de // para simplificar: si (a) ans = b; si no = c; // para


Cristo; // respuesta += valor; simplificar: ans = ans + val; y sus variantes
// índice = (índice + 1) % n; // índice = // índice++; si (índice >= n) índice = 0; //
(índice + n - 1) % n; // respuesta int = (int)
índice--; si (índice < 0) índice = n - 1;
((doble)d + 0.5); // respuesta = // para redondear al entero más cercano
min(respuesta, new_computation); // atajo mínimo/máximo
// forma alternativa pero no utilizada en este libro: ans <?= new_computation; //
algún código usa cortocircuito && (AND) y || (O)

Categorización de problemas

A partir del 24 de mayo de 2013, Steven y Felix, combinados, han resuelto problemas de 1903 UVa (≈46.45% de
todo el conjunto de problemas de UVa). Sobre≈1675 de ellos se discuten y clasifican en este libro. Desde finales de
2011, algunos problemas de Live Archive también se han integrado en UVa Online Judge. En este libro, usamos
ambas cosasnumeraciones de problemas, pero la clave de clasificación principal utilizada en la sección de índice de
este libro es el número de problema UVa.
Estos problemas se clasifican según un'balanceo de carga'esquema: Si un problema se puede
clasificar en dos o más categorías, se ubicará en la categoría con menor número de problemas. De
esta forma, puede encontrar que algunos problemas han sido categorizados 'erróneamente', donde
la categoría en la que aparece puede no coincidir con la técnica que ha utilizado para resolverlo. Solo
podemos garantizar que si ve el problema X en la categoría Y, entonces sabe quenosotroshan logrado
resolver el problema X con la técnica mencionada en la sección que trata sobre la categoría Y.

También hemos limitado cada categoría a un máximo de 25 (VEINTICINCO) problemas, dividiéndolos en


categorías separadas cuando sea necesario.
Si necesita sugerencias para cualquiera de los problemas (que hemos resuelto), pase al práctico índice
que se encuentra al final de este libro en lugar de hojear cada capítulo; podría ahorrarle algo de tiempo. El
índice contiene una lista de problemas de UVa/LA, ordenados por su número de problema (¡haga una
búsqueda binaria!) y aumentado por las páginas que contienen la discusión de dichos problemas (y las
estructuras de datos y/o algoritmos necesarios para resolver ese problema). En la tercera edición,
permitimos que las sugerencias abarquen más de una línea para que puedan ser más significativas.
¡Utilice esta función de categorización para su entrenamiento! Resolver al menos algunos problemas de cada
categoría (especialmente los que hemos destacado comoDeberías intentar *) es una excelente manera de
diversificar su conjunto de habilidades para resolver problemas. Por concisión, nos hemos limitado a un máximo
de 3 destacados por categoría.

xi
CONTENIDO ©
c Steven y Félix

Cambios para la Segunda Edición


Existensustancialcambios entre la primera y la segunda edición de este libro. Como autores, hemos
aprendido varias cosas nuevas y resuelto cientos de problemas de programación durante el intervalo de un
año entre estas dos ediciones. También hemos recibido comentarios de los lectores, especialmente de los
estudiantes de la clase CS3233 de Steven del segundo semestre del año escolar 2010/2011, y hemos
incorporado estas sugerencias en la segunda edición.

Aquí hay un resumen de los cambios importantes para la segunda edición:

• El primer cambio notable es el diseño. Ahora tenemos una mayor densidad de información en cada página.
El 2Dakota del NorteLa edición utiliza interlineado sencillo en lugar del interlineado de 1,5 utilizado en la edición
1.S tedición. También se mejora el posicionamiento de las figuras pequeñas para que tengamos un diseño
más compacto. Esto es para evitar aumentar demasiado el número de páginas y al mismo tiempo agregar
más contenido.

• Se han solucionado algunos errores menores en nuestros ejemplos de código (tanto los que se muestran en el
libro como las copias electrónicas proporcionadas en el sitio web complementario). Todos los ejemplos de código
ahora tienen comentarios mucho más significativos para ayudar en la comprensión.

• Se han corregido varios problemas relacionados con el idioma (tipográficos, gramaticales o


estilísticos).

• Además de mejorar la discusión de muchas estructuras de datos, algoritmos y problemas de


programación, también hemos agregado estosnuevomateriales en cada capítulo:

1. Muchos nuevos problemas Ad Hoc para iniciar este libro (Sección 1.4).
2. Un conjunto ligero de técnicas booleanas (manipulación de bits) (Sección 2.2), Gráficos
implícitos (Sección 2.4.1) y estructuras de datos Fenwick Tree (Sección 2.4.4).
3. Más DP: Una explicación más clara de DP de abajo hacia arriba, elO(norteIniciar sesiónk) solución para
el problema LIS, la suma de mochila/subconjunto 0-1 y DP TSP (utilizando la técnica de máscara de
bits) (Sección 3.5.2).

4. Una reorganización del material del gráfico en: Graph Traversal (tanto DFS como BFS),
árbol de expansión mínimo, rutas más cortas (fuente única y todos los pares), flujo
máximo y gráficos especiales. Los nuevos temas incluyen el algoritmo MST de Prim, una
discusión de DP como un recorrido en DAG implícitos (Sección 4.7.1), Gráficos Eulerianos
(Sección 4.7.3) y el algoritmo de ruta de aumento (Sección 4.7.4).
5. Una reorganización de las técnicas matemáticas (Capítulo 5) en: Ad Hoc, Java
BigInteger, Combinatorics, Number Theory, Probability Theory, Cycle-Finding, Game
Theory (nuevo) y Powers of a (Square) Matrix (nuevo). Cada tema ha sido reescrito
para mayor claridad.
6. Habilidades básicas de procesamiento de cadenas (Sección 6.2), más problemas relacionados con cadenas (Sección
6.3), incluida la coincidencia de cadenas (Sección 6.4) y una explicación mejorada del árbol/
matriz de sufijos (Sección 6.6).

7. Más bibliotecas de geometría (Capítulo 7), especialmente sobre puntos, líneas y polígonos.

8. Un nuevo capítulo 8, que contiene una discusión sobre descomposición de problemas, técnicas de
búsqueda avanzada (A*, búsqueda limitada en profundidad, profundización iterativa, IDA*), técnicas
avanzadas de DP (más técnicas de máscara de bits, el problema del cartero chino, una compilación
de DP comunes estados, una discusión sobre mejores estados de DP y algunos problemas de DP más
difíciles).

XIII
CONTENIDO ©
c Steven y Félix

• Muchas figuras existentes en este libro han sido redibujadas y mejoradas. Se han agregado muchas figuras
nuevas para ayudar a explicar los conceptos con mayor claridad.

• La primera edición está escrita principalmente desde el punto de vista del concursante del ICPC y del
programador de C++. La segunda edición está escrita para ser más equilibrada e incluye la perspectiva del
IIO. La compatibilidad con Java también se ha mejorado considerablemente en la segunda edición. Sin
embargo, no admitimos ningún otro lenguaje de programación hasta el momento.

• El sitio web 'Métodos para resolver' de Steven ahora se ha integrado completamente en este libro en forma
de 'sugerencias de una sola línea' para cada problema y el útil índice de problemas en la parte posterior de
este libro. Ahora, llegar a los 1000 problemas resueltos en UVa online Judge ya no es un sueño
descabellado (creemos que esta hazaña es factible con unserioLicenciatura universitaria de CS de 4 años).

• Algunos ejemplos de la primera edición utilizan problemas de programación antiguos. En la segunda


edición, estos ejemplos se reemplazaron/añadieron con ejemplos más nuevos.

• ≈600 ejercicios de programación más de UVa Online Judge y Live Archive han sido resueltos por
Steven & Felix y agregados a este libro. También hemos agregado muchos más ejercicios
escritos a lo largo del libro con sugerencias/soluciones breves como apéndices.

• Perfiles breves de inventores de estructuras de datos/algoritmos han sido adaptados de Wikipedia


[71] u otras fuentes para este libro. Es bueno saber un poco más sobre estos
inventores.

Cambios para la Tercera Edición


Nos dimos dos años (saltándonos 2012) para preparar unsustancialnúmero de mejoras y
materiales adicionales para la tercera edición de este libro. Aquí está el resumen de los cambios
importantes para la tercera edición:

• La tercera edición ahora usa un tamaño de fuente ligeramente más grande (12 pt) en comparación con la segunda
edición (11 pt), un aumento del 9 por ciento. Con suerte, muchos lectores encontrarán el texto más legible esta
vez. También usamos figuras más grandes. Estas decisiones, sin embargo, han aumentado el número de páginas y
han hecho que el libro sea más grueso. También hemos ajustado el margen izquierdo/derecho en las páginas
pares/impares para aumentar la legibilidad.

• El diseño se ha cambiado para comenzar casi todas las secciones en una página nueva. Esto es para hacer que el
diseño sea mucho más fácil de administrar.

• hemos añadidomucho masejercicios escritos a lo largo del libro y los clasificó ensin estrella(
con fines de autocomprobación; consejos/soluciones están al final de cada capítulo) y
protagonizado *versiones (para desafíos adicionales; no se proporciona ninguna solución). Los
ejercicios escritos se han colocado cerca de la discusión relevante en el cuerpo del texto.

• ≈Steven & Felix han resuelto 477 ejercicios de programación más de UVa Online Judge y Live Archive y, en
consecuencia, se han agregado a este libro. Por lo tanto, hemos mantenido un importante≈50% (para ser
precisos,≈46.Cobertura del 45 % de los problemas del juez en línea UVa incluso cuando el juez ha crecido en
el mismo período de tiempo. Estos nuevos problemas se han enumerado en unfuente cursiva. Algunos de
los problemas más nuevos han reemplazado a los más antiguos a medida queDeberías intentar
problemas. Todos los ejercicios de programación ahora se colocan siempre al final de una sección.

xiv
CONTENIDO ©
c Steven y Félix

• Ahora tenemos pruebas de quecapazLos estudiantes de CS pueden lograr≥500 problemas de AC


(desde 0) en el Juez Online de la UVa en tan solo un semestre Universitario (4 meses) con este libro.

• losnuevo(o revisados), capítulo por capítulo:

1. El Capítulo 1 contiene una introducción más suave para los lectores que son nuevos en la
programación competitiva. Hemos desarrollado formatos de entrada/salida (E/S) más estrictos
en problemas típicos de programación y rutinas comunes para tratar con ellos.

2. Agregamos una estructura de datos lineal más: 'deque' en la Sección 2.2. El Capítulo 2 ahora contiene
una discusión más detallada de casi todas las estructuras de datos discutidas en este capítulo,
especialmente las Secciones 2.3 y 2.4.

3. En el Capítulo 3, tenemos una discusión más detallada de varias técnicas de búsqueda completa:
bucles anidados, generación de subconjuntos/permutaciones iterativamente y retroceso
recursivo. Nuevo: un truco interesante para escribir e imprimir soluciones de DP de arriba hacia
abajo, discusión del algoritmo de Kadane para Max 1D Range Sum.

4. En el Capítulo 4, hemos revisado las etiquetas blanca/gris/negra (heredadas de [7]) a su


nomenclatura estándar, cambiando el nombre de 'flujo máximo' a 'flujo de red' en el proceso.
También nos hemos referido al artículo científico real del autor del algoritmo para una mejor
comprensión de las ideas originales del algoritmo. Ahora tenemos nuevos diagramas del DAG
implícito en problemas clásicos de DP que se encuentran en la Sección 3.5.

5. Capítulo 5: Hemos incluido una mayor cobertura de problemas matemáticos Ad Hoc, una
discusión de una interesante operación Java BigInteger:es probableprimo, Se agregaron/
ampliaron varias fórmulas de combinatoria de uso común y se modificaron algoritmos de
tamiz, se ampliaron/revisaron secciones sobre Teoría de la probabilidad (Sección 5.6),
Búsqueda de ciclos (Sección 5.7) y Teoría de juegos (Sección 5.8).

6. Capítulo 6: Reescribimos la Sección 6.6 para tener una mejor explicación de Suffix Trie/
Tree/ Array reintroduciendo el concepto de carácter terminal.
7. Capítulo 7: Recortamos este capítulo en dos secciones principales y mejoramos la calidad del código de la
biblioteca.

8. Capítulo 8: Los temas más difíciles que se enumeraron en el Capítulo 1-7 en el 2Dakota del NorteLa edición
ahora se ha reubicado en el Capítulo 8 (o el Capítulo 9 a continuación). Nuevo: Discusión de la rutina
de retroceso más difícil, búsqueda de espacio de estado, encuentro en el medio, truco de usar BST
balanceado como tabla de notas y una sección más completa sobre la descomposición del problema.

9. Nuevo Capítulo 9: Se han agregado varios temas raros que aparecen de vez en cuando en los
concursos de programación. Algunos de ellos son fáciles, pero muchos de ellos son difíciles y pueden
ser determinantes de puntaje algo importantes en los concursos de programación.

Sitios web de apoyo


Este libro tiene un sitio web oficial complementario ensitios.google.com/site/stevenhalim, desde donde
puede obtener una copia digital del código fuente de muestra y el (versión pública/más simple) de las)
diapositivas en PDF utilizadas en las clases CS3233 de Steven.

Todos los ejercicios de programación de este libro están integrados en eluhunt.felix-halim.netherramienta y


se puede encontrar en el Juez en línea de la UVa enuva.onlinejudge.org

Nuevo en la tercera edición: muchos algoritmos ahora tienen visualizaciones interactivas


en: www.comp.nus.edu.sg/~stevenha/visualización

XV
CONTENIDO ©
c Steven y Félix

Agradecimientos a la Primera Edición


De Steven:quiero agradecer

• Dios, Jesucristo y el Espíritu Santo, por darme talento y pasión en la programación


competitiva.

• mi encantadora esposa, Grace Suryani, por permitirme dedicar nuestro valioso tiempo a este
proyecto.

• mi hermano menor y coautor, Felix Halim, por compartir muchas estructuras de datos,
algoritmos y trucos de programación para mejorar la escritura de este libro.

• mi padre Lin Tjie Fong y mi madre Tan Hoey Lan por criarnos y animarnos a hacer
bien nuestro estudio y trabajo.

• la Escuela de Informática de la Universidad Nacional de Singapur, por


contratarme y permitirme enseñar el módulo CS3233 - 'Programación
competitiva' del que nació este libro.

• Profesores/conferencistas de NUS/ex-NUS que han dado forma a mis habilidades de entrenamiento y


programación competitiva: Prof. Andrew Lim Leong Chye, Prof. asociado Tan Sun Teck, Aaron Tan
Tuck Choy, Prof. asociado Sung Wing Kin, Ken, Dr. Alan Cheng Holun.

• mi amiga Ilham Winata Kurnia por la lectura de prueba del manuscrito de la primera edición.

• compañeros Asistentes de enseñanza de CS3233 y ACM ICPC Trainers @ NUS: Su Zhan, Ngo
Minh Duc, Melvin Zhang Zhiyong, Bramandia Ramadhana.

• mis estudiantes de CS3233 en Sem2 AY2008/2009 que me inspiraron para crear las notas
de clase y estudiantes en Sem2 AY2009/2010 que verificaron el contenido de la primera
edición de este libro y dieron la contribución inicial de Live Archive

Agradecimientos por la Segunda Edición


De Steven:Además, también quiero agradecer

• el primero≈550 compradores de la 1ª edición a partir del 1 de agosto de 2011 (este número ya no se


actualiza). ¡Sus respuestas de apoyo nos alientan!

xvi
CONTENIDO ©
c Steven y Félix

• un compañero Asistente de enseñanza de CS3233 @ NUS: Victor Loh Bo Huai.

• mis estudiantes de CS3233 en Sem2 AY2010/2011 que contribuyeron en los aspectos


técnicos y de presentación de la segunda edición, en orden alfabético: Aldrian Obaja Muis,
Bach Ngoc Thanh Cong, Chen Juncheng, Devendra Goyal, Fikril Bahri, Hassan Ali Askari,
Harta Wijaya, Hong Dai Thanh, Koh Zi Chun, Lee Ying Cong, Peter Phandi, Raymond Hendy
Susanto, Sim Wenlong Russell, Tan Hiang Tat, Tran Cong Hoang, Yuan Yuan y otro
estudiante que prefiere permanecer en el anonimato.

• los correctores de pruebas: Siete de los estudiantes CS3233 arriba (subrayados) más Tay Wenbin.

• Por último, pero no menos importante, quiero volver a agradecer a mi esposa, Grace Suryani, por dejarme hacer
otra ronda del tedioso proceso de edición de libros mientras estaba embarazada de nuestro primer bebé: Jane
Angelina Halim.

Agradecimientos por la Tercera Edición


De Steven:Nuevamente, quiero agradecer

• la≈2000 compradores de la 2ª edición al 24 de mayo de 2013 (este número ya no se


actualiza). Gracias :).

xvii
CONTENIDO ©
c Steven y Félix

• compañero Asistente de enseñanza de CS3233 @ NUS en los últimos dos años: Harta
Wijaya, Trinh Tuan Phuong y Huang Da.

• mis estudiantes de CS3233 en Sem2 AY2011/2012 que contribuyeron en los aspectos


técnicos y de presentación de la segunda edición de este libro, en orden alfabético: Cao
Sheng, Chua Wei Kuan, Han Yu, Huang Da, Huynh Ngoc Tai, Ivan Reinaldo, John Goh Choo
Ern, Le Viet Tien, Lim Zhi Qin, Nalin Ilango, Nguyen Hoang Duy, Nguyen Phi Long, Nguyen
Quoc Phong, Pallav Shinghal, Pan Zhengyang, Pang Yan Han, Song Yangyu, Tan Cheng
Yong Desmond, Tay Wenbin, Yang Mansheng, Zhao Yang, Zhou Yiming y otros dos
estudiantes que prefieren permanecer en el anonimato.

• los lectores de prueba: Seis de los estudiantes CS3233 en Sem2 AY2011/2012 (subrayado) y
Hubert Teo Hua Kian.

• mis estudiantes de CS3233 en Sem2 AY2012/2013 que contribuyeron en los aspectos


técnicos y de presentación de la segunda edición de este libro, en orden alfabético:
Arnold Christopher Koroa, Cao Luu Quang, Lim Puay Ling Pauline, Erik Alexander
Qvick Faxaa, Jonathan Darryl Widjaja, Nguyen Tan Sy Nguyen, Nguyen Truong Duy,
Ong Ming Hui, Pan Yuxuan, Shubham Goyal, Sudhanshu Khemka, Tang Binbin, Trinh
Ngoc Khanh, Yao Yujian, Zhao Yue y Zheng Naijia.

• el Centro NUS para el Desarrollo de la Enseñanza y el Aprendizaje (CDTL) por brindar el


financiamiento inicial para construir el sitio web de visualización de algoritmos.

• mi esposa Grace Suryani y mi hija Jane Angelina por su amor en nuestra familia.

Por un futuro mejor de la


humanidad, stevenyFélix Halim
Singapur, 24 de mayo de 2013

Derechos de autor

Ninguna parte de este libro puede ser reproducida o transmitida de ninguna forma o por ningún medio, ya sea
electrónica o mecánicamente, incluidas las fotocopias, el escaneo, la carga en cualquier sistema de
almacenamiento y recuperación de información.

xviii
CONTENIDO ©
c Steven y Félix

Perfiles de los autores

Dr. Steven Halim1


stevenhalim@gmail.com
Steven Halim es actualmente profesor en la
Escuela de Informática de la Universidad
Nacional de Singapur (SoC, NUS). Imparte varios
cursos de programación en NUS, que van desde
metodología de programación básica,
estructuras de datos intermedios y algoritmos, y
también el módulo de 'Programación
competitiva' que utiliza este libro. Es el
entrenador de los equipos NUS ACM ICPC y del
equipo IOI de Singapur. Participó en varios ACM
ICPC Regional como estudiante (Singapur 2001,
Aizu 2003, Shanghai 2004). Hasta ahora, él y
otros entrenadores @ NUS han preparado con
éxito dos equipos finalistas mundiales de ACM
ICPC (2009-2010; 2012-2013), así como dos
medallistas de oro, seis de plata y siete de
bronce del IOI (2009-2012).
Steven está felizmente casado con Grace
Suryani Tioso y actualmente tiene una hija:
Jane Angelina Halim.

Félix Halim, PhD2


felix.halim@gmail.com
Felix Halim ahora tiene un doctorado de SoC, NUS. En términos de
concursos de programación, Felix tiene una reputación mucho más
colorida que su hermano mayor. Fue concursante de IOI 2002 (en
representación de Indonesia). Sus equipos ICPC (en ese momento, la
Universidad Bina Nusantara) participaron en ACM ICPC Manila Regional
2003-2004-2005 y obtuvieron los puestos 10, 6 y 10 respectivamente.
Luego, en su último año, su equipo finalmente ganó ACM ICPC Kaohsiung
Regional 2006 y así se convirtió en finalista mundial de ACM ICPC en Tokio
2007 (lugar 44). Hoy, se une activamente a TopCoder Single Round
Matches y su calificación más alta es unamarillodescifrador. Ahora trabaja
en Google, Mountain View, Estados Unidos de América.

1Tesis doctoral: "Un enfoque integrado de caja blanca + negra para diseñar y ajustar algoritmos de búsqueda

local estocásticos", 2009.


2Tesis Doctoral: “Resolviendo Problemas de Big Data: de Secuencias a Tablas y Gráficos”, 2012.

xix
CONTENIDO ©
c Steven y Félix

abreviaturas LSB:Bit menos significativo

MCBM:Coincidencia máxima de bip de


cardinalidad MCM:Multiplicación de cadenas de
matrices MMCM:Costo mínimo Flujo máximo MAL
A*:Una estrella
:Conjunto Máximo Independiente MLE:Límite de
MCA:Asociación de Maquinaria de Cómputo
memoria excedido MPC:Cobertura de ruta mínima
C.A.:Aceptado
MSB:Parte más significante MSSP:Rutas más
APSP:Rutas más cortas de todos los pares
cortas de fuentes múltiples MST:Árbol de
AVL:Adelson-Velskii Landis (BST)
expansión mínimo MWIS:Conjunto independiente
BNF:Formulario Backus Naur BFS: ponderado máximo MVC:Cobertura mínima de
Búsqueda primero en amplitud BI: vértice
Entero grande UN POCO:Árbol
indexado binario BST:Árbol de
DO:Juez en línea
búsqueda binaria

EDUCACIÓN FÍSICA:Error de presentación


CC:Cambio de moneda CCW:En
sentido anti-horario FC: RB:Rojo-Negro (BST) precio de venta al público:
Frecuencia acumulada CH:Casco Consulta de rango mínimo (o máximo) RSQ:Consulta
convexo CS:Ciencias de la de suma de rango RTE:Error de tiempo de ejecución
Computación CW:Agujas del
reloj
SSSP:Rutas más cortas de fuente única SA:
TROZO DE CUERO:Gráfico Acíclico Dirigido Matriz de sufijos SPOJ:Juez en línea de
DAT:Tabla de direccionamiento directo Esfera S T:Árbol de sufijos
CORRIENTE CONTINUA:Divide y
conquistaras SFD:Primera búsqueda en STL:Biblioteca de plantillas estándar
profundidad DLS:Búsqueda de profundidad
limitada DP:Programación dinámica SD: TLE:Límite de tiempo excedido
Estructura de datos
USACO:Olimpiada de computación de EE.
disfunción eréctil:Editar distancia UU. UVa:Universidad de Valladolid [47]

FIFO:Primero en entrar primero en Washington:Respuesta

salir PIE:Árbol de Fenwick incorrecta WF:finales mundiales

MCD:Máximo común divisor

CIPC:Concurso Progresivo Universitario Internacional


DNI:Búsqueda de profundización iterativa AIF*:
Profundización iterativa de una estrella IIO:Olimpiada
Internacional de Informática IPSC:Concurso de
resolución de problemas de Internet

LA:Archivo en vivo [33] ACV:Ancestro


común más bajo MCM:Minimo común
multiplo LCP:Prefijo común más largo LCS
1:Subsecuencia común más larga LCS2:

Subcadena común más larga LIFO:Último


en entrar primero en salir

LIS:Subsecuencia creciente más larga


LRS:Subcadena repetida más larga

XX
Lista de tablas

1 No en el plan de estudios de IOI [20]Aún. . . . . . . . . . . . . . . . . . . . . . . . . . . ix


2 Plan de lección del CS3233 de Steven. . . . . . . . . . . . . . . . . . . . . . . . . X

1.1 Tipos de problemas regionales recientes de ACM ICPC (Asia) . . . . . . . . . . . . . . 5


1.2 Tipos de problemas (forma compacta) . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Ejercicio: Clasifique estos problemas de UVa . . . . . . . . . . . . . . . . . . . . . 6
1.4 Regla general para el 'peor algoritmo de CA' para varios tamaños de entradanorte. . . . 8

2.1 Ejemplo de tabla de frecuencias acumuladas. . . . . . . . . . . . . . . . . . . 59


2.2 Comparación entre el árbol de segmentos y el árbol de Fenwick. . . . . . . . . . . . . 63

3.1 Ejecución del método de bisección en la función de ejemplo. . . . . . . . . . . . . 86


3.2 Tabla de decisiones de DP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.3 UVa 108 - Suma Máxima . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
3.4 Resumen de problemas clásicos de DP en esta sección. . . . . . . . . . . . . . 114
3.5 Comparación de técnicas de resolución de problemas (solo regla general) . . . . . . 120

4.1 Lista de terminologías gráficas importantes. . . . . . . . . . . . . . . . . . . . . 121


4.2 Tabla de decisión del algoritmo de recorrido de gráfico . . . . . . . . . . . . . . . . . . . 135
4.3 Tabla DP de Floyd Warshall. . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
4.4 Tabla de decisión del algoritmo SSSP/APSP. . . . . . . . . . . . . . . . . . . . . 161
4.5 Caracteres utilizados en UVa 11380 . . . . . . . . . . . . . . . . . . . . . . . . . . 169

5.1 Lista dealgunotérminos matemáticos discutidos en este capítulo. . . . . . . . . . 191


5.2 Parte 1: Encontrarkλ,F(X) = (3×X+1)%4,X0=7 . . . . . . . . . . . . . . . 224
5.3 Parte 2: Encontrarm. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
5.4 Parte 3: Encontrarλ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

6.1 L/R: antes/después de la clasificación; k = 1; aparece el orden ordenado inicial. . . . . . 255


6.2 L/R: antes/después de la clasificación; k = 2; 'GATAGACA'y 'GACA'se intercambian. . . 256
6.3 Antes/Después de la clasificación; k = 4; ningún cambio . . . . . . . . . . . . . . . . . . . . . 257
6.4 Coincidencia de cadenas usando Suffix Array . . . . . . . . . . . . . . . . . . . . . . . 260
6.5 Cálculo del LCP dada la SA deT = 'GATAGACA$' . . . . . . . . . . . . 261
6.6 Suffix Array, LCP y propietario deT = 'GATAGACA$CATA#' . . . . . . . . 262

9.1 La Reducción de LCA a RMQ. . . . . . . . . . . . . . . . . . . . . . . 360


9.2 Ejemplos de expresiones de infijo, prefijo y sufijo. . . . . . . . . . . . . . . 376
9.3 Ejemplo de cálculo de sufijo. . . . . . . . . . . . . . . . . . . . . . . . 376
9.4 Ejemplo de Ejecución de Algoritmo de Patio de Maniobras. . . . . . . . . . . . . 377

xxx
Lista de Figuras

1.1 Ilustración de UVa 10911 - Formación de equipos de prueba. . . . . . . . . . . . . . . . 2


1.2 UVa Online Judge y ACM ICPC Live Archive. . . . . . . . . . . . . . . . 15
1.3 USACO Training Gateway y Sphere Online Judge . . . . . . . . . . . . . dieciséis

1.4 Algunas referencias que inspiraron a los autores a escribir este libro. . . . . . . . . 31

2.1 Visualización de máscara de bits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36


2.2 Ejemplos de BST. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.3 Visualización de montones (máx.) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.4 Visualización de la estructura de datos de gráficos. . . . . . . . . . . . . . . . . . . . . . . 49
2.5 Ejemplos de gráficos implícitos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.6unionSet(0, 1)→(2, 3)→(4, 3)yes el Mismo Conjunto (0, 4) . . . . . . . 53
2.7unionSet(0, 3)→encontrarConjunto(0) . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.8 Árbol de segmentos del arreglo A ={18, 17, 13, 19, 15, 11, 20}yRMQ(1, 3) . . . 56
2.9 Árbol de segmentos del arreglo A ={18, 17, 13, 19, 15, 11, 20}yRMQ(4, 6) . . . 56
2.10 Actualización de la matriz A para{18, 17, 13, 19, 15,99, 20}. . . . . . . . . . . . . . . 57
2.11 Ejemplo dersq(6) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.12 Ejemplo dersq(3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.13 Ejemplo deajustar (5, 1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

3.1 8-Reinas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
3,2 UVa 10360 [47] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.3 Mi antepasado (se ordenan las 5 rutas de la raíz a la hoja) . . . . . . . . . . . . . . . . 85
3.4 Visualización de UVa 410 - Balance de la Estación. . . . . . . . . . . . . . . . . . . 90
3.5 UVa 410 - Observaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
3.6 UVa 410 - Solución codiciosa. . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.7 UVa 10382 - Hierba de riego. . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.8 PD ascendente (no se muestran las columnas 21 a 200) . . . . . . . . . . . . . . 100
3.9 Subsecuencia creciente más larga . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.10 Cambio de moneda. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
3.11 Un gráfico completo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
3.12 Ilustración de cortar palos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

4.1 Gráfico de muestra. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122


4.2 UVa 11902 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
4.3 Ejemplo de animación de BFS. . . . . . . . . . . . . . . . . . . . . . . . . . . 124
4.4 Un ejemplo de DAG. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
4.5 Animación de DFS cuando se ejecuta en el gráfico de muestra de la figura 4.1. . . . . . 129
4.6 Introducción de dos atributos Más DFS:número de dfsydfs bajo. . . . . . . . . 131
4.7 Encontrar puntos de articulación connúmero de dfsydfs bajo. . . . . . . . . . . . 131
4.8 Encontrar puentes, también connúmero de dfsydfs bajo. . . . . . . . . . . . . . . . 132
4.9 Un ejemplo de un gráfico dirigido y sus SCC. . . . . . . . . . . . . . . . 134

XXII
LISTA DE FIGURAS ©
c Steven y Félix

4.10 Ejemplo de un problema MST. . . . . . . . . . . . . . . . . . . . . . . . . . 138


4.11 Animación del algoritmo de Kruskal para un problema MST. . . . . . . . . . . . 139
4.12 Animación del algoritmo de Prim para el mismo gráfico que en la figura 4.10—izquierda. . 140
4.13 De izquierda a derecha: MST, 'Máximo' ST, 'Mínimo' SS, MS 'Bosque'. . . . 141
4.14 Segundo Mejor ST (desde UVa 10600 [47]) . . . . . . . . . . . . . . . . . . . . . 142
4.15 Encontrar el segundo mejor árbol de expansión del MST. . . . . . . . . . . . 142
4.16 Minimax (UVa 10048 [47]) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.17 Animación de Dijkstra en un gráfico ponderado (de UVa 341 [47]) . . . . . . . . 149
4.18 -ve Peso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
4.19 Bellman Ford puede detectar la presencia de ciclo negativo (de UVa 558 [47]) 151
4.20 Explicación de Floyd Warshall 1 . . . . . . . . . . . . . . . . . . . . . . . . . 156
4.21 Explicación de Floyd Warshall 2 . . . . . . . . . . . . . . . . . . . . . . . . . 156
4.22 Explicación de Floyd Warshall 3 . . . . . . . . . . . . . . . . . . . . . . . . . 157
4.23 Explicación de Floyd Warshall 4 . . . . . . . . . . . . . . . . . . . . . . . . . 157
4.24 Ilustración de flujo máximo (UVa 820 [47] - Problema E de la final mundial de ICPC 2000) . 163
4.25 El método de Ford Fulkerson implementado con DFS puede ser lento. . . . . . . . 164
4.26 ¿Cuál es el valor de Max Flow de estos tres gráficos residuales? . . . . . . . . . 165
4.27 Gráfico residual de UVa 259 [47] . . . . . . . . . . . . . . . . . . . . . . . . . 166
4.28 Técnica de división de vértices. . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
4.29 Algunos casos de prueba de UVa 11380 . . . . . . . . . . . . . . . . . . . . . . . . . . 168
4.30 Modelado de gráfico de flujo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
4.31 Gráficos especiales (L-to-R): DAG, Tree, Eulerian, Bipartite Graph . . . . . . . 171
4.32 La ruta más larga en este DAG. . . . . . . . . . . . . . . . . . . . . . . . . 172
4.33 Ejemplo de conteo de rutas en DAG - Bottom-Up . . . . . . . . . . . . . . . 172
4.34 Ejemplo de conteo de rutas en DAG - Top-Down . . . . . . . . . . . . . . . . 173
4.35 El gráfico general dado (izquierda) se convierte en DAG. . . . . . . . . . . . . 174
4.36 El gráfico/árbol general dado (izquierda) se convierte en DAG. . . . . . . . . . 175
4.37 Cambio de moneda como rutas más cortas en DAG .................... 176
4.38 0-1 Mochila como rutas más largas en DAG .................... 177
4.39 UVa 10943 como rutas de conteo en DAG ..................... 177
4.40 A: SSSP (Parte de APSP); B1-B2: Diámetro del árbol .............. 179
4.41 Euleriano. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
4.42 El problema de emparejamiento bipartito se puede reducir a un problema de flujo máximo. . . . . 181
4.43 Variantes de MCBM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
4.44 Algoritmo de ruta de aumento. . . . . . . . . . . . . . . . . . . . . . . . . . . 183

5.1 Izquierda: Triangulación de un Polígono Convexo, Derecha: Caminos Monotónicos. . . . . . 206


5.2 Árbol de decisión para una instancia del 'Juego de Euclides'. . . . . . . . . . . . . . . . 226
5.3 Árbol de decisión parcial para una instancia de 'Un juego de multiplicación'. . . . . . . 227

6.1 Ejemplo:A = 'ACAATCC'yB = 'AGCATGC' (puntuación de alineación = 7). . . . 246


6.2 Sufijo Trie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
6.3 Sufijos, trino de sufijos y árbol de sufijos deT = 'GATAGACA$' . . . . . . . . . . . 250
6.4 Coincidencia de cadenas deT = 'GATAGACA$'con varias cadenas de patrones. . . . . 251
6.5 Subcadena repetida más larga deT = 'GATAGACA$' . . . . . . . . . . . . . . .252
6.6 ST generalizado deT1= 'GATAGACA$'yT2= 'CATÁ#'y su LCS. . 253
6.7 Clasificación de los sufijos deT = 'GATAGACA$' . . . . . . . . . . . . . . . . . . . .254
6.8 Árbol de sufijos y matriz de sufijosT = 'GATAGACA$' . . . . . . . . . . . . . . .254

7.1 Punto giratorio (10, 3) 180 grados en sentido antihorario alrededor del origen (0, 0) 272
7.2 Distancia a la Línea (izquierda) y al Segmento de Línea (centro); Producto cruzado (derecha) 274

XXIII
LISTA DE FIGURAS ©
c Steven y Félix

7.3 Círculos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277


7.4 Circunferencia por 2 puntos y radio . . . . . . . . . . . . . . . . . . . . . . . 278
7.5 Triángulos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
7.6 Incircunferencia y Circunferencia de un Triángulo. . . . . . . . . . . . . . . . . . . . . 280
7.7 Cuadriláteros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
7.8 Izquierda: polígono convexo, derecha: polígono cóncavo . . . . . . . . . . . . . . . . 286
7.9 Arriba a la izquierda: adentro, Arriba a la derecha: también adentro, Abajo: afuera . . . . . . . . . . . 287
7.10 Izquierda: Antes del Corte, Derecha: Después del Corte . . . . . . . . . . . . . . . . . . . . . . . 288
7.11 Analogía de la banda elástica para encontrar un casco convexo. . . . . . . . . . . . . . . . 289
7.12 Clasificación de un conjunto de 12 puntos por sus ángulos con un pivote (Punto 0) . . . . . . . 290
7.13 La parte principal del algoritmo de exploración de Graham. . . . . . . . . . . . . . . . . . 291
7.14 Explicación de Circunferencia por 2 puntos y radio . . . . . . . . . . . . . 295

8.1 5 Problema de Queens: El estado inicial . . . . . . . . . . . . . . . . . . . . . . . 300


8.2 Problema de 5 reinas: Después de colocar la primera reina . . . . . . . . . . . . . . . . 301
8.3 Problema de 5 reinas: Después de colocar la segunda reina . . . . . . . . . . . . . . . 301
8.4 Problema de 5 reinas: Después de colocar la tercera reina . . . . . . . . . . . . . . . . 302
8.5 N-Queens, después de colocar la cuarta y la quinta reina. . . . . . . . . . . . 302
8.6 Visualización de UVa 1098 - Robots on Ice. . . . . . . . . . . . . . . . . . . 304
8.7 Caso 1: Ejemplo cuandosestá a dos pasos det. . . . . . . . . . . . . . . 307
8.8 Caso 2: Ejemplo cuandosestá a cuatro pasos det. . . . . . . . . . . . . . . 307
8.9 Caso 3: Ejemplo cuandosestá a cinco pasos det. . . . . . . . . . . . . . . 307
8.10 15 Rompecabezas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
8.11 El Camino de Descenso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
8.12 Ilustración para ACM ICPC WF2010 - J - Sharing Chocolate . . . . . . . . . 317
8.13 Pista de Atletismo (desde UVa 11646) . . . . . . . . . . . . . . . . . . . . . . . . 321
8.14 Ilustración para ACM ICPC WF2009-A-Un enfoque cuidadoso. . . . . . . . 326

9.1 El gráfico de implicación del ejemplo 1 (izquierda) y el ejemplo 2 (derecha) . . . . . 336


9.2 El TSP estándar frente al TSP bitónico. . . . . . . . . . . . . . . . . . . . . 339
9.3 Un ejemplo del problema del cartero chino. . . . . . . . . . . . . . . . . . . 342
9.4 Las cuatro variantes comunes de coincidencia de gráficos en concursos de programación. 349
9.5 Un caso de prueba de muestra de UVa 10746: 3 coincidencias con un costo mínimo = 40 . . . . 350
9.6 L: Esfera, M: Hemisferio y círculo máximo, R: gcDistancia (Arco AB) . . . . 352
9.7 Comparación entre el máximo de rutas independientes y el máximo de rutas disjuntas de borde. 354
9.8 Un ejemplo de un árbol enraizadoTconnorte=10 vértices. . . . . . . . . . . . . . 359
9.9 La estrategia de construcción del cuadrado mágico para Oddnorte. . . . . . . . . . . . . . 361
9.10 Un ejemplo del problema de flujo mínimo de costo máximo (MCMF) (UVa 10594 [47]) . . 369
9.11 Cobertura mínima de ruta en DAG (de UVa 1201 [47]) . . . . . . . . . . . . . . . . . 370
9.12 Ejemplo de eliminación de un árbol AVL (Borrar 7) . . . . . . . . . . . . . . . . . . 382
9.13 Explicación deRMQ(i, j) . . . . . . . . . . . . . . . . . . . . . . . . . . . .388

A.1 Estadísticas de Steven al 24 de mayo de 2013. . . . . . . . . . . . . . . . . . . . . . 393


A.2 Buscando los siguientes problemas más fáciles usando 'dacu'. . . . . . . . . . . . . . . . . 394
A.3 Podemos rebobinar concursos pasados con 'concurso virtual'. . . . . . . . . . . . . . . 394
A.4 Los ejercicios de programación de este libro están integrados en uHunt. . . . . . . 395
A.5 Progreso de Steven y Felix en el juez en línea UVa (2000-presente) . . . . . . . . 395
A.6 Andrian, Felix y Andoko Ganaron ACM ICPC Kaohsiung 2006 . . . . . . . . 395

XXIV
Capítulo 1

Introducción

¡Quiero competir en las finales mundiales de ACM ICPC!


— Un estudiante dedicado

1.1 Programación competitiva


La directriz central en 'Programación Competitiva' es esta: “Dados los problemas bien conocidos de Ciencias
de la Computación (CS), ¡resuélvelos lo más rápido posible!”.
Vamos a digerir los términos uno por uno. El término 'problemas de CS conocidos' implica que en la
programación competitiva, estamos tratando conresueltoproblemas de CS ynoproblemas de investigación (donde
las soluciones aún se desconocen). Algunas personas (al menos el autor del problema) definitivamente han
resuelto estos problemas antes. 'Resolverlos' implica que1debemos impulsar nuestro conocimiento de CS a un
cierto nivel requerido para que podamos producir un código de trabajo que también pueda resolver estos
problemas, al menos en términos de obtener elmismosalida como el autor del problema usando el secreto del
autor del problema2datos de prueba dentro del límite de tiempo estipulado. La necesidad de resolver el problema
"lo más rápido posible" es donde radica el elemento competitivo: la velocidad es una meta muy natural en el
comportamiento humano.

Una ilustración: UVa Online Judge [47] Problema número 10911 (Formación de equipos de prueba).

Descripción abreviada del problema:

Sean (x, y) las coordenadas de la casa de un estudiante en un plano 2D. Hay 2norte
estudiantes y queremosparellos ennortegrupos Dejardiser el dista∑nce entre las casas
de 2 alumnos en grupoi. Formanortegrupos tales quecosto= i=1diesminimizado.
norte

Salida el mínimocosto. Restricciones: 1≤norte≤8 y 0≤x, y≤1000.


Entrada de muestra:
norte=2; Coordenadas de los 2norte=4 casas son{1,1},{8,6},{6,8}, y{1,3}.
Salida de muestra:
costo=4.83.
¿Puedes resolver este problema?
Si es así, ¿cuántos minutos necesitaría para completar el código de trabajo? ¡Piense e
intente no voltear esta página inmediatamente!

1Algunas competencias de programación se realizan en equipo para fomentar el trabajo en equipo, ya que los ingenieros de software
generalmente no trabajan solos en la vida real.
2Al ocultar los datos de prueba reales del enunciado del problema, la programación competitiva alienta a los

solucionadores de problemas a ejercitar su fuerza mental para pensar en todos los casos posibles del problema y probar
sus programas con esos casos. Esto es típico en la vida real, donde los ingenieros de software tienen que probar mucho su
software para asegurarse de que cumple con los requisitos establecidos por los clientes.

1
1.1. PROGRAMACIÓN COMPETITIVA ©
c Steven y Félix

Figura 1.1: Ilustración de UVa 10911 - Formación de equipos de prueba

Ahora pregúntate: ¿Cuál de los siguientes te describe mejor? Tenga en cuenta que si no tiene
claro el material o la terminología que se muestra en este capítulo, puede volver a leerlo
después de leer este libro una vez.
• Programador no competitivo A (también conocido como el borroso):
Paso 1: Lee el problema y se confunde. (Este problema es nuevo para él). Paso
2: intenta codificar algo: lee la entrada y la salida no triviales.
Paso 3: Se da cuenta de que todos sus intentos sonnoAceptado (CA):
Codicioso(Sección 3.4): Emparejar repetidamente a los dos estudiantes restantes con las
distancias de separación más cortas da laRespuesta incorrecta (WA).
IngenuoBúsqueda completa: Usando el retroceso recursivo (Sección 3.2) y probando todos los
rendimientos de emparejamiento posiblesLímite de tiempo excedido (TLE).

• Programador no competitivo B (Renunciar):


Paso 1: Lee el problema y se da cuenta de que ha visto este problema antes. Pero
también recuerda que no ha aprendido a resolver este tipo de problemas... No es
consciente de laProgramación Dinámica (DP)solución (Sección 3.5)... Paso 2: Salta
el problema y lee otro problema en el conjunto de problemas.
• (Todavía) Programador no competitivo C (Lento):
Paso 1: Lee el problema y se da cuenta de que es un problema difícil:'concordancia perfecta
de peso mínimo en un pequeño gráfico ponderado general'. Sin embargo, dado que el
tamaño de entrada es pequeño, este problema se puede resolver utilizando DP. El estado DP
es unmáscara de bitsque describe un estado coincidente y estudiantes coincidentes no
coincidentes iyjencenderá dos bitsiyjen la máscara de bits (Sección 8.3.1).
Paso 2: Codifica la rutina de E/S, escribe DP de arriba hacia abajo recursivo, pruebas,depura>.<...
Paso 3:Despues de 3 horas, su solución obtiene AC (pasó todos los datos de prueba secretos).

• Programador competitivo D:
Completa todos los pasos tomados por el programador no competitivo C en≤30 minutos.

• Programador muy competitivo E:


Un programador muy competitivo (por ejemplo, los codificadores 'objetivo' rojos en TopCoder [32])
resolvería este problema 'bien conocido'≤15 minutos...

Tenga en cuenta que estar bien versado en la programación competitiva esnoel objetivo final, sino sólo un
medio para un fin. El verdadero objetivo final es producir científicos/programadores informáticos completos
que estén mucho más preparados para producir un mejor software y enfrentar problemas de investigación
de informática más difíciles en el futuro. Los fundadores del ACM International Collegiate Programming
Contest (ICPC) [66] tienen esta visión y nosotros, los autores, estamos de acuerdo con ella. Con este libro,
jugamos nuestro pequeño papel en la preparación de las generaciones actuales y futuras para que sean
más competitivos en el tratamiento de los conocidos problemas de CS planteados con frecuencia en los
recientes ICPC y la Olimpiada Internacional de Informática (IOI).

2
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

Ejercicio 1.1.1: La estrategia codiciosa del programador no competitivo A anterior realmente funciona para
el caso de prueba de muestra que se muestra en la Figura 1.1. por favor da unmejorcontraejemplo!

Ejercicio 1.1.2: Analice la complejidad temporal de la ingenua solución de búsqueda completa del
programador no competitivo A anterior para comprender por qué recibe el veredicto de TLE.

Ejercicio 1.1.3*: En realidad, una solución inteligente de retroceso recursivocon podatodavía puede resolver
este problema. ¡Resuelva este problema sin usar una tabla DP!

1.2 Consejos para ser Competitivo


Si se esfuerza por ser como los programadores competitivos D o E como se ilustra arriba, es decir, si desea
ser seleccionado (a través de→selecciones nacionales) para participar y obtener una medalla en el IOI [34], o
para ser uno de los miembros del equipo que represente a su Universidad en el ACM ICPC [66] (nacionales→
regionales→y hasta la final mundial), o para obtener buenos resultados en otros concursos de
programación, ¡entonces este libro es definitivamente para usted!
En los capítulos siguientes, aprenderá todo, desde lo básico hasta lo intermedio o incluso lo avanzado.3
estructuras de datos y algoritmos que han aparecido con frecuencia en concursos de programación
recientes, compilados de muchas fuentes [50, 9, 56, 7, 40, 58, 42, 60, 1, 38, 8, 59, 41, 62, 46] (ver Figura 1.4).
No solo aprenderá los conceptos detrás de las estructuras de datos y los algoritmos, sino también cómo
implementarlos de manera eficiente y aplicarlos a los problemas de concurso apropiados. Además de eso,
también aprenderá muchos consejos de programación derivados de nuestras propias experiencias que
pueden ser útiles en situaciones de concurso. Comenzamos este libro brindándole varios consejos
generales a continuación:

1.2.1 Sugerencia 1: ¡Escriba el código más rápido!

¡En serio! Aunque este consejo puede no significar mucho ya que ICPC y (especialmente) IOI no son
concursos de mecanografía, hemos visto Rankiy rangoi+1 equipos ICPC separados solo por unos minutos y
concursantes frustrados de IOI que se pierden de salvar puntos importantes al no poder codificar una
solución de fuerza bruta de último minuto correctamente. Cuando pueda resolver la misma cantidad de
problemas que su competidor, se deberá a la habilidad de codificación (su capacidad para producir código
conciso y sólido) y... la velocidad de escritura.
Pruebe esta prueba de mecanografía enhttp://www.typingtest.comy siga las instrucciones allí sobre cómo
mejorar su habilidad de escritura. el de steven es∼85-95 palabras por minuto y Felix es∼55-65 palabras por minuto.
Si su velocidad de escritura es mucho menor que estos números, ¡tome este consejo en serio!
Además de poder escribir caracteres alfanuméricos de forma rápida y correcta, también
deberá familiarizar sus dedos con las posiciones de los caracteres del lenguaje de programación
de uso frecuente: paréntesis () o{}o corchetes [] o corchetes angulares<>, el punto y coma ; y dos
puntos:, comillas simples '' para caracteres, comillas dobles "" para cadenas, el ampersand &, la
barra vertical o la 'tubería'|, el signo de exclamación !, etc.
Como un poco de práctica, intente escribir el código fuente de C++ a continuación lo más rápido posible.

# incluir <algoritmo> // si tiene problemas con este código C++, //


# incluir <cmath> consulte primero sus libros de texto de programación...
# incluir <cstdio>
# incluir <ccadena>
utilizando el espacio de nombres estándar;

3Si percibe que el material presentado en este libro es de dificultad intermedia o avanzada depende de
su habilidad de programación antes de leer este libro.

3
1.2. CONSEJOS PARA SER COMPETITIVO ©
c Steven y Félix

/* Formando Quiz Teams, la solución para UVa 10911 arriba */


// usar variables globales es una mala práctica de ingeniería de software,
int N, target; // pero está bien para la programación competitiva
doble dist[20][20], memo[1 << 16]; // 1 << 16 = 2 1̂6, tenga en cuenta que max N = 8

coincidencia doble (máscara de bits int) { // estado DP = máscara de bits


// inicializamos 'memo' con -1 en la función principal
si (memo[máscara de bits] > -0.5) // este estado ha sido calculado antes
devolver memo[máscara de bits]; // simplemente busque la tabla de notas //
if (máscara de bits == objetivo) todos los estudiantes ya están emparejados
devolver memo[máscara de bits] = 0; // el costo es 0

respuesta doble = 2000000000.0; // inicializar con un valor grande


entero p1, p2;
para (p1 = 0; p1 < 2 * N; p1++)
si (!(máscara de bits & (1 << p1)))
descanso; // encuentra el primer bit que está apagado
para (p2 = p1 + 1; p2 < 2 * N; p2++) // entonces, intenta hacer coincidir p1
si (!(máscara de bits & (1 << p2))) // con otro bit p2 que también está apagado
respuesta = min(respuesta, // elegir el minimo
dist[p1][p2] + coincidencia (máscara de bits | (1 << p1) | (1 << p2)));

return memo[máscara de bits] = ans; // almacena el resultado en una tabla de notas y regresa
}

int principal() {
int i, j, caseNo = 1, x[20], y[20]; //
freopen("10911.txt", "r", stdin); // redirigir archivo de entrada a stdin

while (escanear("%d", &N), N) { // sí, podemos hacer esto :)


para (i = 0; i < 2 * N; i++)
scanf("%*s %d %d", &x[i], &y[i]); para // '%*s' salta nombres
(i = 0; i < 2 * N - 1; i++) // construye una tabla de distancias
para (j = i + 1; j < 2 * N; j++) por pares // ¿has usado 'hipot' antes?
dist[i][j] = dist[j][i] = hipot(x[i] - x[j], y[i] - y[j]);

// usa DP para resolver la coincidencia perfecta ponderada mínima en un gráfico general


pequeño para (i = 0; i < (1 << 16); i++) memo[i] = -1.0; // establecer -1 en todas las celdas
destino = (1 << (2 * N)) - 1;
printf("Caso %d: %.2lf\n", caseNo++, coincidencia(0)); } } //
devuelve 0;

Para su referencia, la explicación de esta solución de 'Programación dinámica con máscara de


bits' se encuentra en la Sección 2.2, 3.5 y 8.3.1. No te alarmes si aún no lo entiendes.

1.2.2 Sugerencia 2: identificar rápidamente los tipos de problemas

En los ICPC, los concursantes (equipos) reciben unestablecerde problemas (≈7-12 problemas) de diferentes tipos.
A partir de nuestra observación de conjuntos de problemas recientes de la región de Asia del CIPC, podemos
categorizar los tipos de problemas y su tasa de aparición como en la Tabla 1.1.

4
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

En los IOI, los concursantes reciben 6 tareas en 2 días (8 tareas en 2 días en 2009-2010) que cubren los puntos 1-5
y 10, con unmucho más pequeñasubconjunto de elementos 6-10 en la Tabla 1.1. Para obtener más información,
consulte el plan de estudios del IOI de 2009 [20] y la clasificación de problemas del IOI de 1989-2008 [67].

Ninguna Categoria En este libro Frecuencia


1. Ad Hoc Sección 1.4 1-2
2. Búsqueda Completa (Iterativa/Recursiva) Sección 3.2 1-2
3. Divide y vencerás Sección 3.3 0-1
4. Codiciosos (generalmente los originales) Sección 3.4 0-1
5. Programación Dinámica (generalmente las originales) Sección 3.5 1-3
6. Gráfico Capítulo 4 1-2
7. Matemáticas Capítulo 5 1-2
8. Procesamiento de cadenas Capítulo 6 1
9. Geometría Computacional Capítulo 7 1
10. Algunos problemas más difíciles/raros Capítulo 8-9 1-2
Total en conjunto 8-17 (≈≤12)
Tabla 1.1: Tipos de problemas regionales recientes de ACM ICPC (Asia)

La clasificación en la Tabla 1.1 está adaptada de [48] y de ninguna manera completa. Algunas técnicas,
por ejemplo, 'clasificación', no se clasifican aquí porque son 'triviales' y generalmente se usan solo
como una 'subrutina' en un problema mayor. No incluimos 'recursividad' ya que está incrustada en
categorías como retroceso recursivo o programación dinámica. También omitimos las 'estructuras de
datos' ya que el uso de una estructura de datos eficiente puede considerarse integral para resolver
problemas más difíciles. Por supuesto, los problemas a veces requieren técnicas mixtas: un problema
se puede clasificar en más de un tipo. Por ejemplo, el algoritmo de Floyd Warshall es a la vez una
solución para el problema gráfico de All-Pairs Shortest Paths (APSP, Sección 4.5) y un algoritmo de
Programación Dinámica (DP) (Sección 3.5). Los algoritmos de Prim y Kruskal son soluciones para el
árbol de expansión mínimo (MST, Sección 4. 3) problema gráfico y algoritmos Greedy (Sección 3.4). En
la Sección 8.4, discutiremos problemas (más difíciles) que requieren más de un algoritmo y/o
estructuras de datos para ser resueltos.
En el futuro (cercano), estas clasificaciones pueden cambiar. Un ejemplo significativo es la programación
dinámica. Esta técnica no se conocía antes de la década de 1940, ni se usaba con frecuencia en ICPC o IOI antes de
mediados de la década de 1990, pero hoy en día se considera un requisito previo definitivo. A modo de ilustración:
Había≥3 problemas de PD (de 11) en la reciente final mundial del ICPC 2010.
Sin embargo, el objetivo principal esnosimplemente asociar problemas con las técnicas requeridas para
resolverlos como en la Tabla 1.1. Una vez que esté familiarizado con la mayoría de los temas de este libro,
también podrá clasificar los problemas en los tres tipos de la tabla 1.2.

Ninguna Categoria Confianza y velocidad de resolución esperada


A. He resuelto este tipo antes Estoy seguro de que puedo volver a resolverlo (y rápido)
B. He visto este tipo antes Pero esa vez sé que todavía no puedo resolverlo
C. No he visto este tipo antes Vea la discusión a continuación

Tabla 1.2: Tipos de problemas (forma compacta)

Ser - estarcompetitivo, eso es,hacer bienen un concurso de programación, debe ser capaz de clasificar
problemas con confianza y frecuencia como tipo A y minimizar la cantidad de problemas que clasifica en
tipo B. Es decir, necesita adquirir suficiente conocimiento de algoritmos y desarrollar sus habilidades de
programación para que pueda considerar muchos problemas clásicos para ser fácil. Sin embargo, avictoria
un concurso de programación, también necesitarás desarrollar habilidadeshabilidades para resolver
problemas (por ejemplo, reducir el problema dado a un problema conocido, identificar pistas sutiles o

5
1.2. CONSEJOS PARA SER COMPETITIVO ©
c Steven y Félix

propiedades en el problema, atacando el problema desde un ángulo no obvio, etc.) para que usted (o
su equipo) pueda derivar la solución requerida a un problema duro/original de tipo C en IOI o ICPC
Regionales/Finales mundiales y hacer asi quedentro dela duración del concurso.

UVa Título Tipo de problema Insinuación

10360 ataque de rata Búsqueda completa o DP Sección 3.2


10341 Resuélvelo Sección 3.3
11292 Dragón de Loowater Sección 3.4
11450 Compras para bodas Sección 3.5
10911 Formación de equipos de prueba DP con máscara de bits Sección 8.3.1
11635 Reserva de hotel Sección 8.4
11506 programador enojado Sección 4.6
10243 ¡Fuego! ¡¡Fuego!! ¡¡¡Fuego!!! Sección 4.7.1
10717 menta Sección 8.4
11512 GATTACA Sección 6.6
10065 Empacadores de mosaicos inútiles Sección 7.3.7

Tabla 1.3: Ejercicio: Clasifique estos problemas de UVa

Ejercicio 1.2.1: Lea los problemas UVa [47] que se muestran en la Tabla 1.3 y determine sus tipos de
problemas. Dos de ellos han sido identificados para usted. Llenar esta tabla es fácil después de dominar
este libro; todas las técnicas necesarias para resolver estos problemas se analizan en este libro.

1.2.3 Sugerencia 3: Hacer análisis de algoritmos

Una vez que haya diseñado un algoritmo para resolver un problema particular en un concurso de programación,
debe hacerse esta pregunta: dado el límite de entrada máximo (generalmente dado en una buena descripción del
problema), ¿puede el algoritmo desarrollado actualmente, con su complejidad de tiempo/espacio , pasar el límite
de tiempo/memoria dado para ese problema en particular?
A veces, hay más de una forma de atacar un problema. Algunos enfoques pueden ser incorrectos, otros no lo
suficientemente rápidos y otros 'exagerados'. Una buena estrategia es hacer una lluvia de ideas para muchos
algoritmos posibles y luego elegir ella solución más simple que funciona(es decir, es lo suficientemente rápido
como para pasar el límite de tiempo y memoria y aun así producir la respuesta correcta)4!
Las computadoras modernas son bastante rápidas y pueden procesar5hasta≈100METRO(o 108; 1METRO=
1,000,000) operaciones en pocos segundos. Puede usar esta información para determinar si su algoritmo se
ejecutará a tiempo. Por ejemplo, si el tamaño de entrada máximonortees 100k(o 105; 1k=1,000), y su
algoritmo actual tiene una complejidad de tiempo deO(norte2), el sentido común (o su calculadora) le
informará que (100k)2o 1010es un número muy grande que indica que su algoritmo requerirá (del orden de)
cientos de segundos para ejecutarse. Por lo tanto, deberá diseñar un algoritmo más rápido (y también
correcto) para resolver el problema. Supongamos que encuentra uno que se ejecuta con una complejidad de
tiempo deO(norteIniciar sesión2norte). Ahora, su calculadora le informará que 105Iniciar sesión2105
es solo 1.7×106y el sentido común dicta que el algoritmo (que ahora debería ejecutarse en menos de un
segundo) probablemente podrá pasar el límite de tiempo.

4Discusión: es cierto que en los concursos de programación, elegir el algoritmo más simple que funcione es crucial para obtener buenos
resultados en ese concurso de programación. Sin embargo, durantesesiones de entrenamiento, donde las limitaciones de tiempo no son un
problema, puede ser beneficioso dedicar más tiempo a tratar de resolver un determinado problema utilizando elmejor algoritmo posible.
Estamos mejor preparados de esta manera. Si nos encontramos con una versión más difícil del problema en el futuro, ¡tendremos más
posibilidades de obtener e implementar la solución correcta!
5Trata esto como una regla general. Estos números pueden variar de una máquina a otra.

6
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

Los límites del problema son tan importantes como la complejidad temporal de su algoritmo para
determinar si su solución es adecuada. Suponga que solo puede diseñar un algoritmo relativamente simple
de codificar que se ejecuta con una complejidad de tiempo horrenda deO(norte4). Esto puede parecer una
solución inviable, pero sinorte≤50, entonces realmente has resuelto el problema. Puedes implementar tuO(
norte4) algoritmo con impunidad desde 504son solo 6.25METROy su algoritmo aún debería ejecutarse en
alrededor de un segundo.
Tenga en cuenta, sin embargo, que el orden de complejidad no indica necesariamente el número real
de operaciones que requerirá su algoritmo. Si cada iteración involucra una gran cantidad de operaciones
(muchos cálculos de coma flotante o una cantidad significativa de subbucles constantes), o si su
implementación tiene una 'constante' alta en su ejecución (bucles repetidos innecesariamente o pases
múltiples, o incluso si /O o sobrecarga de ejecución), su código puede tardar más en ejecutarse de lo
esperado. Sin embargo, este no suele ser el caso, ya que los autores del problema deberían haber diseñado
los límites de tiempo para que un algoritmo bien codificado con una complejidad de tiempo adecuada logre
un veredicto AC.
Al analizar la complejidad de su algoritmo con el límite de entrada dado y el límite de
tiempo/memoria establecido, puede decidir mejor si debe intentar implementar su
algoritmo (lo que llevará un tiempo precioso en los ICPC e IOI), intentar mejorar su
algoritmo primero, o cambiar a otros problemas en el conjunto de problemas.
Como se mencionó en el prefacio de este libro, vamos anodiscutir el concepto de análisis
algorítmico en detalles. Nosotrosasumirque ya tienes esta habilidad básica. Hay una multitud de
otros libros de referencia (por ejemplo, "Introducción a los algoritmos" [7], "Diseño de
algoritmos" [38], "Algoritmos" [8], etc.) que lo ayudarán a comprender los siguientes conceptos
previos/ técnicas en análisis algorítmico:

• Análisis básico de complejidad temporal y espacial para algoritmos iterativos y recursivos:

– Un algoritmo conk-bucles anidados de aproximadamentenorteiteraciones que cada uno tieneO(nortek) complejidad.

– Si su algoritmo es recursivo conbllamadas recursivas por nivel y tieneLniveles, el


algoritmo tiene aproximadamenteO(bL) complejidad, pero este es solo un límite superior
aproximado. La complejidad real depende de qué acciones se realizan por nivel y si es
posible la poda.

– Un algoritmo de programación dinámica u otra rutina iterativa que procesa un 2Dnorte×


nortematriz enO(k) por celda se ejecuta enO(k×norte2) tiempo. Esto se explica con más
detalle en la Sección 3.5.

• Técnicas de análisis más avanzadas:

– Demostrar la corrección de un algoritmo (especialmente para los algoritmos Greedy en la Sección


3.4), para minimizar la posibilidad de obtener el veredicto de 'Respuesta incorrecta'.

– Realice el análisis amortizado (por ejemplo, consulte el Capítulo 17 de [7]), aunque rara vez se usa en
concursos, para minimizar la posibilidad de obtener el veredicto 'Límite de tiempo excedido', o peor
aún, considerando que su algoritmo es demasiado lento y omite el problema cuando de hecho, es lo
suficientemente rápido en el sentido amortizado.

– Realice un análisis sensible a la salida para analizar el algoritmo que (también) depende del tamaño
de la salida y minimice la posibilidad de obtener el veredicto 'Límite de tiempo excedido'. Por
ejemplo, un algoritmo para buscar una cadena con longitudmetroen una cadena larga con la ayuda
de un árbol de sufijos (que ya está construido) se ejecuta enO(metro+occ) tiempo. El tiempo que
tarda este algoritmo en ejecutarse no solo depende del tamaño de entradametrosino también el
tamaño de salida: el número de ocurrenciasocc(ver más detalles en la Sección 6.6).

7
1.2. CONSEJOS PARA SER COMPETITIVO ©
c Steven y Félix

• Familiaridad con estos límites:


– 210=1,024≈103, 220=1,048,576≈106.
– enteros de 32 bits con signo (En t)y enteros con signo de 64 bits (largo largo)tienen límites
superiores de 231−1≈2×109(seguro para hasta≈9 dígitos decimales) y 263−1≈9×1018
(seguro para hasta≈18 dígitos decimales) respectivamente.

– Se pueden usar enteros sin signo si solo se requieren números no negativos. enteros
sin signo de 32 bits (int sin firmar)y enteros sin signo de 64 bits (largo largo sin
firmar)tienen límites superiores de 232−1≈4×109y 264−1≈1.8×1019respectivamente.
– Si necesita almacenar números enteros≥264, utilice la técnica Big Integer (Sección 5.3).
– Existennorte! permutaciones y 2nortesubconjuntos (o combinaciones) denorteelementos.

– La mejor complejidad temporal de un algoritmo de clasificación basado en comparación es Ω(norteIniciar sesión2norte).

– Normalmente,O(norteIniciar sesión2norte) los algoritmos son suficientes para resolver la mayoría de los problemas de concursos.

– El tamaño de entrada más grande para problemas típicos de concursos de programación debe ser<1
METRO. Más allá de eso, el tiempo necesario para leer la entrada (la rutina de Entrada/Salida) será el
cuello de botella.

– Una CPU típica del año 2013 puede procesar 100METRO=108operaciones en pocos segundos.

Muchos programadores novatos se saltarían esta fase e inmediatamente comenzarían a implementar el primer
algoritmo (ingenuo) que se les ocurriera solo para darse cuenta de que la estructura de datos o el algoritmo
elegido no es lo suficientemente eficiente (o incorrecto). Nuestro consejo para los concursantes del ICPC6:
Absténgase de codificar hasta que esté seguro de que su algoritmo es correcto y lo suficientemente rápido.

norte El peor algoritmo de CA Comentario


≤[10..11] O(norte!), oh(norte6) por ejemplo, enumerar permutaciones (Sección 3.2)
≤[15..18] O(2norte×norte2) por ejemplo, DP TSP (Sección 3.5.2)
≤[18..22] O(2norte×norte) por ejemplo, DP con técnica de máscara de bits (Sección 8.3.1)
≤100 O(norte4) por ejemplo, DP con 3 dimensiones +O(norte) círculo,norteCk=4
≤400 O(norte3) por ejemplo, Floyd Warshall (Sección 4.5)
≤2k O(norte2Iniciar sesión2 por ejemplo, 2 bucles anidados + un DS relacionado con el árbol (Sección 2.3)

≤10k norte) O(norte2) por ejemplo, Burbuja/Selección/Ordenación por inserción (Sección 2.2)

≤1METRO O(norteIniciar sesión2norte) p. ej. Merge Sort, construyendo Segment Tree (Sección 2.3) La mayoría de los

≤100METRO O(norte), oh(Iniciar sesión2norte), oh(1) problemas de concursos tienennorte≤1METRO(cuello de botella de E/S)

Tabla 1.4: Complejidades de tiempo de la regla empírica para el 'peor algoritmo de CA' para varios tamaños de
entrada de caso úniconorte, asumiendo que su CPU puede calcular 100METROartículos en 3s.

Para ayudarlo a comprender el crecimiento de varias complejidades de tiempo comunes y, por lo tanto, ayudarlo a
juzgar qué tan rápido es 'suficiente', consulte la Tabla 1.4. También se encuentran variantes de tales tablas en
muchos otros libros sobre estructuras de datos y algoritmos. Esta tabla está escrita a partir de unperspectiva del
concursante de programación. Por lo general, las restricciones de tamaño de entrada se dan en una (buena)
descripción del problema. Suponiendo que una CPU típica puede ejecutar cien millones de operaciones en
alrededor de 3 segundos (el límite de tiempo típico en la mayoría de los problemas de UVa [47]), podemos predecir
el 'peor' algoritmo que aún puede pasar el límite de tiempo. Por lo general, el algoritmo más simple tiene la menor
complejidad de tiempo, pero si puede pasar el límite de tiempo, ¡utilícelo!

6A diferencia de ICPC, las tareas de IOI generalmente se pueden resolver (parcial o totalmente) utilizando varias soluciones posibles, cada
una con diferentes complejidades de tiempo y puntajes de subtareas. Para ganar puntos valiosos, puede ser bueno usar una solución de
fuerza bruta para anotar algunos puntos y comprender mejor el problema. No habrá una penalización de tiempo significativa ya que IOI no
es una competencia de velocidad. Luego, mejore iterativamente la solución para ganar más puntos.

8
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

En la Tabla 1.4, vemos la importancia de usar buenos algoritmos con pequeños órdenes de crecimiento, ya que nos
permiten resolver problemas con tamaños de entrada más grandes. Pero un algoritmo más rápido generalmente no es
trivial y, a veces, es sustancialmente más difícil de implementar. En la Sección 3.2.3, discutimos algunos consejos que
pueden permitir el uso de la misma clase de algoritmos con tamaños de entrada más grandes. En capítulos posteriores,
también explicamos algoritmos eficientes para varios problemas de computación.

Ejercicio 1.2.2: responda las siguientes preguntas utilizando su conocimiento actual sobre los
algoritmos clásicos y sus complejidades temporales. Una vez que haya terminado de leer este libro
una vez, puede ser beneficioso intentar este ejercicio nuevamente.

1. Haynortepáginas web (1≤norte≤10METRO). Cada página webitiene un rango de páginari. Desea elegir
las 10 páginas principales con los rangos de página más altos. ¿Qué método es mejor?

(a) Cargar todonorteel rango de página de las páginas web en la memoria, ordénelas (Sección 2.2) en orden descendente
de rango de página, obteniendo los 10 primeros.

(b) Use una estructura de datos de cola de prioridad (un montón) (Sección 2.3).

2. Dado unMETRO×nortematriz enteraq(1≤M, N≤30), determinar si existe una submatriz


deqde tamañoA×B(1≤A≤METRO,1≤B≤norte) dóndesignificar(q) = 7.

(a) Pruebe todas las submatrices posibles y compruebe si la media de cada submatriz es 7. Este
algoritmo se ejecuta enO(METRO3× norte3).

(b) Pruebe todas las submatrices posibles, pero enO(METRO2×norte2) con esta técnica: .

3. Dada una lista L con 10knúmeros enteros, necesitasfrecuentementeobtenersuma(i, j),es


decir, la suma deL[i] + L[i+1] + ...+ L[j].¿Qué estructura de datos debería usar?

(a) Matriz simple (Sección 2.2).


(b) Matriz simple preprocesada con programación dinámica (Sección 2.2 y 3.5).
(c) Árbol de búsqueda binaria balanceada (Sección 2.3).

(d) Montón binario (Sección 2.3).

(e) Árbol de segmentos (Sección 2.4.3).

(f) Árbol indexado binario (Fenwick) (Sección 2.4.4).


(g) Árbol de Sufijos (Sección 6.6.2) o su alternativa, Matriz de Sufijos (Sección 6.6.4).

4. Dado un conjuntoSdenortepuntosal azardispersos en un plano 2D (2≤norte≤1000), encuentra dos


puntos∈Sque tienen la mayor distancia euclidiana de separación. es unO(norte2) algoritmo de
búsqueda completo que prueba todos los posibles pares factibles?

(a) Sí, tal búsqueda completa es posible.


(b) No, debemos encontrar otra manera. Debemos usar: .

5. Debe calcular el camino más corto entre dos vértices en un gráfico acíclico dirigido (DAG)
ponderado con|V |, |E|≤100k. ¿Qué algoritmo(s) se pueden usar en un concurso de
programación típico (es decir, con un límite de tiempo de aproximadamente 3 segundos)?

(a) Programación dinámica (Sección 3.5, 4.2.5 y 4.7.1).


(b) Búsqueda primero en amplitud (Sección 4.2.2 y 4.4.2).

(c) de Dijkstra (Sección 4.4.3).

9
1.2. CONSEJOS PARA SER COMPETITIVO ©
c Steven y Félix

(d) Bellman Ford's (Sección 4.4.4).


(e) Floyd Warshall (Sección 4.5).

6. ¿Qué algoritmo produce una lista de los primeros 10knúmeros primos con la mejor complejidad
de tiempo? (Sección 5.5.1)

(a) Criba de Eratóstenes (Sección 5.5.1).


(b) Para cada númeroi∈[1..10k], prueba siesPrime(i)es verdadero (Sección 5.5.1).

7. Quieres probar si el factorial denorte, es decirnorte! es divisible por un enterometro. 1≤norte≤10000.


¿Qué debes hacer?

(a) Pruebe sinorte! %metro==0.

(b) El enfoque ingenuo anterior no funcionará, use: (Sección 5.5.1).

8. Pregunta 4, pero con un conjunto más amplio de puntos:norte≤1METROy una restricción


adicional: Los puntos sondispersos al azaren un plano 2D.

(a) Todavía se puede utilizar la búsqueda completa mencionada en la pregunta 3.

(b) El enfoque ingenuo anterior no funcionará, use: (Sección 7.3.7).

9. Desea enumerar todas las ocurrencias de una subcadenaPAGS(de longitudmetro) en una cadena (larga) T(de
longitudnorte), Si alguna. Ambas cosasnorteymetrotener un máximo de 1 millón de caracteres.

(a) Use el siguiente fragmento de código C++:

para (int i = 0; i < n; i++) {


booleano encontrado = verdadero;

para (int j = 0; j < m && encontrado; j++)


if (i + j >= n || P[j] != T[i + j]) encontrado = falso; if
(encontrado) printf("P se encuentra en el índice %d en T\n", i);
}

(b) El enfoque ingenuo anterior no funcionará, use: (Sección 6.4 o 6.6).

1.2.4 Consejo 4: Lenguajes de programación maestros


Hay varios lenguajes de programación compatibles con ICPC7, incluidos C/C++ y Java. ¿Qué
lenguajes de programación se debe aspirar a dominar?
Nuestra experiencia nos da esta respuesta: preferimos C ++ con su biblioteca de plantillas estándar (STL)
incorporada, pero aún necesitamos dominar Java. Aunque es más lento, Java tiene potentes bibliotecas integradas
y API, como BigInteger/BigDecimal, GregorianCalendar, Regex, etc. Los programas Java son más fáciles de depurar
con la capacidad de la máquina virtual para proporcionar un seguimiento de la pila.

7Opinión personal: De acuerdo con las últimas reglas de la competencia IOI 2012, Java todavía no es compatible

con IOI. Los lenguajes de programación permitidos en IOI son C, C++ y Pascal. Por otro lado, las Finales Mundiales
del ICPC (y por lo tanto la mayoría de las Regionales) permiten el uso de C, C++ y Java en el concurso. Por lo tanto,
parece que el 'mejor' lenguaje para dominar es C++, ya que es compatible con ambas competencias y tiene un
fuerte soporte STL. Si los concursantes de IOI eligen dominar C++, tendrán la ventaja de poder usar el mismo
lenguaje (con un mayor nivel de dominio) para ACM ICPC en sus actividades de nivel universitario.

10
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

cuando falla (a diferencia de los volcados del núcleo o las fallas de segmentación en C/C++). Por otro lado, C/
C++ también tiene sus propios méritos. Dependiendo del problema en cuestión, cualquiera de los idiomas
puede ser la mejor opción para implementar una solución en el menor tiempo posible.
¡Suponga que un problema requiere que calcule 25! (el factorial de 25). La respuesta es muy grande:
15.511.210.043.330.985.984.000.000. Esto supera con creces el tipo de datos entero primitivo incorporado
más grande (sin firmar largo largo:264−1). Como todavía no hay una biblioteca aritmética de precisión
arbitraria integrada en C/C++, habríamos tenido que implementar una desde cero. El código Java, sin
embargo, es extremadamente simple (más detalles en la Sección 5.3). En este caso, el uso de Java
definitivamente reduce el tiempo de codificación.

importar java.util.Scanner;
importar java.math.BigInteger;

clase principal { // nombre de clase Java estándar en UVa OJ


public static void main(String[] args) {
BigInteger fac = BigInteger.ONE;
para (int i = 2; i <= 25; i++)
fac = fac.multiply(BigInteger.valueOf(i)); // ¡Está en la biblioteca!
Sistema.salida.println(fac);
}}

También es importante dominar y comprender la capacidad total de su lenguaje de programación favorito.


Tome este problema con un formato de entrada no estándar: la primera línea de entrada es un número
enteronorte. Esto es seguido pornortelíneas, cada una de las cuales comienza con el carácter '0', seguida de
un punto '.', seguida de un número desconocido de dígitos (hasta 100 dígitos) y finalmente termina con tres
puntos '...'.

3
0.1227...
0.517611738...
0.7341231223444344389923899277...

Una posible solución es la siguiente:

# incluir <cstdio>
utilizando el espacio de nombres estándar;

int N; // usar variables globales en concursos puede ser una buena estrategia //
charx[110]; acostúmbrese a establecer el tamaño de la matriz un poco más grande de lo necesario

int principal() {
escaneo("%d\n", &N);
mientras (N--) { // simplemente hacemos un bucle desde N, N-1, N-2, ..., 0 //
scanf("0.%[0-9]...\n", &x); '&' es opcional cuando x es una matriz de caracteres
// nota: si te sorprende el truco anterior, // comprueba los
detalles de scanf en www.cppreference.com
printf("los digitos son 0.%s\n", x); } } //
devuelve 0;

Código fuente:ch1 01 factorial.java; ch1 02 scanf.cpp

11
1.2. CONSEJOS PARA SER COMPETITIVO ©
c Steven y Félix

No muchos programadores de C/C++ conocen las capacidades parciales de expresión regular integradas en
la biblioteca de E/S estándar de C. A pesar de queescanear/imprimirson rutinas de E/S de estilo C, todavía se
pueden usar en código C++. Muchos programadores de C++ se 'obligan' a usarcin / couttodo el tiempo
aunque a veces no es tan flexible comoescanear/imprimiry también es mucho más lento.
En los concursos de programación, especialmente en los ICPC, el tiempo de codificación debenoser el
principal cuello de botella. Una vez que descubra el 'peor algoritmo de CA' que pasará el límite de tiempo
dado, ¡se espera que pueda traducirlo en un código sin errores y rápido!
¡Ahora, pruebe algunos de los ejercicios a continuación! Si necesita más de 10 líneas de código para resolver
cualquiera de ellos, ¡debe volver a visitar y actualizar su conocimiento de su(s) lenguaje(s) de programación! El
dominio de los lenguajes de programación que utiliza y sus rutinas incorporadas es extremadamente importante y
lo ayudará mucho en los concursos de programación.

Ejercicio 1.2.3: Producir código de trabajo que eslo más conciso posiblepara las siguientes tareas:

1. UsandoJava, leído en un doble (por


ejemplo1.4732, 15.324547327,etc.)
repetirlo, pero con un ancho de campo mínimo de 7 y 3 dígitos después del punto decimal
(p. ej.ss1.473 (dónde 's'denota un espacio),s15.325,etc.)

2. Dado un número enteronorte(norte≤15), imprimirπanortedígitos después del punto decimal (redondeado). (por
ejemplo, paranorte=2, imprimir3.14;pornorte=4, imprimir3.1416;pornorte=5, impresiones3.14159.)

3. Dada una fecha, determine el día de la semana (lunes, . . . , domingo) de ese día. (por ejemplo, el 9 de
agosto de 2010, la fecha de lanzamiento de la primera edición de este libro, es un lunes).

4. dadonorteenteros aleatorios, imprima los enteros distintos (únicos) en orden ordenado.

5. Dadas las distintas y válidas fechas de nacimiento denortepersonas como triples (DD, MM, AAAA), ordénelas primero
por meses de nacimiento ascendentes (MM), luego por fechas de nacimiento ascendentes (DD) y finalmente por
edad ascendente.

6. Dada una lista deordenadoenterosLde tamaño hasta 1METROelementos, determinar si un valorv


existe enLcon no más de 20 comparaciones (más detalles en la Sección 2.2).

7. Genere todas las permutaciones posibles de{'A B C', . . . , 'J'}, el primeronorte=10 letras
del alfabeto (ver Sección 3.2.1).

8. Genere todos los subconjuntos posibles de{0, 1, 2, . . . ,norte-1}, pornorte=20 (ver Sección 3.2.1).

9. Dada una cadena que representa un número en base X, conviértala en una cadena
equivalente en base Y, 2≤X, Y≤36. Por ejemplo: “FF” en base X = 16 (hexadecimal) es “255”
en baseY1=10 (decimal) y “11111111” en baseY2=2 (binario). Consulte la Sección 5.3.2.

10. Definamos una 'palabra especial' como un alfabeto en minúsculas seguido de dos dígitos consecutivos. Dada una
cadena, reemplace todas las 'palabras especiales' de longitud 3 con 3 estrellas "***", por ejemplo
S = “línea: a70 y z72 serán reemplazadas, aa24 y a872 no”
debe transformarse en:
S = “línea: *** y *** serán reemplazados, aa24 y a872 no”.

11. Dado unválidoexpresión matemática que incluye '+', '-', '*', '/', '(' y ')' en una sola línea,
evalúe esa expresión. (por ejemplo, una expresión bastante complicada pero válida3 + (8 -
7.5) * 10 / 5 - (2 + 5 * 7)debe producir -33.0cuando se evalúa con precedencia de
operadores estándar).

12
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

1.2.5 Consejo 5: Domine el arte de probar el código


Pensaste que habías resuelto un problema en particular. Usted identificó su tipo de problema, diseñó
el algoritmo para él, verificó que el algoritmo (con las estructuras de datos que usa) se ejecutará en el
tiempo (y dentro de los límites de la memoria) al considerar la complejidad del tiempo (y el espacio) e
implementó el algoritmo, pero su solución aún no es Aceptada (AC).
Dependiendo del concurso de programación, puede o no obtener crédito por resolver el problema
parcialmente. En ICPC, solo obtendrá puntos por un problema en particular si el código de su equipo resuelve
todoslos casos de prueba secretos para ese problema. Otros veredictos como Error de presentación (PE),
Respuesta incorrecta (WA), Límite de tiempo excedido (TLE), Límite de memoria excedido (MLE), Error de tiempo de
ejecución (RTE), etc. no aumentan los puntos de su equipo. En el IOI actual (2010-2012), se utiliza el sistema de
puntuación de subtareas. Los casos de prueba se agrupan en subtareas, generalmente variantes más simples de
la tarea original con límites de entrada más pequeños. Solo se le acreditará por resolver una subtarea si su código
resuelve todos los casos de prueba en ella. te danfichasque puede usar (con moderación) a lo largo del concurso
para ver la evaluación de su código por parte del juez.
En cualquier caso, deberá poder diseñar casos de prueba buenos, completos y complicados. La
muestra de entrada-salida dada en la descripción del problema es trivial por naturaleza y, por lo
tanto, generalmente no es un buen medio para determinar la corrección de su código.
En lugar de desperdiciar envíos (y, por lo tanto, acumular tiempo o penalizaciones de puntaje) en ICPC o
tokens en IOI, es posible que desee diseñar casos de prueba complicados para probar su código en su
propia máquina.8. Asegúrese de que su código pueda resolverlos correctamente (de lo contrario, no tiene
sentido enviar su solución, ya que es probable que sea incorrecta, a menos que desee probar los límites de
los datos de prueba).
Algunos entrenadores alientan a sus alumnos a competir entre sí mediante el diseño de casos de prueba. Si los casos de
prueba del estudiante A pueden descifrar el código del estudiante B, entonces A obtendrá puntos de bonificación. Es posible que
desee probar esto en el entrenamiento de su equipo :).
Aquí hay algunas pautas para diseñar buenos casos de prueba a partir de nuestra experiencia.
Estos son típicamente los pasos que han tomado los autores de problemas.

1. Sus casos de prueba deben incluir los casos de prueba de muestra, ya que se garantiza que la salida de
muestra sea correcta. Usar 'FC'en Windows o 'diferencia'en UNIX para verificar la salida de su código
(cuando se le da la entrada de muestra) contra la salida de muestra. Evite la comparación manual, ya que
los humanos son propensos a cometer errores y no son buenos para realizar tales tareas, especialmente
para problemas con formatos de salida estrictos (por ejemplo, línea en blancoEntrecasos de prueba versus
después de cadaCasos de prueba). Para hacer esto,copiar y pegarla entrada de muestra y la salida de
muestra de la descripción del problema, luego guárdelas en archivos (llamados como 'aporte'y 'producción'
o cualquier otra cosa que sea sensata). Luego, después de compilar su programa (supongamos que el
nombre del ejecutable es 'g++'defecto 'a.fuera'),ejecútelo con una redirección de E/S: './a.out < entrada >
misalida'.Finalmente, ejecuta 'diff mi salida de salida'para resaltar cualquier diferencia (potencialmente
sutil), si existe alguna.

2. Para problemas con múltiples casos de prueba en una sola ejecución (consulte la Sección 1.3.2),
debe incluir dos casos de prueba de muestra idénticos consecutivamente en la misma
ejecución. Ambos deben generar las mismas respuestas correctas conocidas. Esto ayuda a
determinar si olvidó inicializar alguna variable; si la primera instancia produce la respuesta
correcta pero la segunda no, es probable que no haya restablecido sus variables.

3. Sus casos de prueba deben incluir casos de esquina complicados. Piense como el autor del problema e
intente encontrar la peor entrada posible para su algoritmo mediante la identificación de casos.

8Los entornos de los concursos de programación difieren de un concurso a otro. Esto puede poner en desventaja a los
concursantes que confían demasiado en el elegante entorno de desarrollo integrado (IDE) (por ejemplo, Visual Studio, Eclipse, etc.)
para la depuración. Puede ser una buena idea practicar la codificación con solo uneditor de textoy uncompilador!

13
1.2. CONSEJOS PARA SER COMPETITIVO ©
c Steven y Félix

que están "ocultos" o implícitos en la descripción del problema. Estos casos generalmente se incluyen en
los casos de prueba secretos del juez, peronoen la entrada y salida de la muestra. Los casos de esquina
típicamente ocurren en valores extremos tales comonorte=0,norte=1, valores negativos, valores finales (y/o
intermedios) grandes que no se ajustan a enteros con signo de 32 bits, etc.

4. Sus casos de prueba deben incluirlargocasos. Aumente el tamaño de entrada gradualmente hasta los
límites de entrada máximos establecidos en la descripción del problema. Use casos de prueba
grandes con estructuras triviales que sean fáciles de verificar con cálculo manual y grandesaleatorio
casos de prueba para probar si su código termina a tiempo y aún produce un resultado razonable (ya
que sería difícil verificar la corrección aquí). A veces, su programa puede funcionar para casos de
prueba pequeños, pero produce una respuesta incorrecta, falla o excede el límite de tiempo cuando
aumenta el tamaño de entrada. Si eso sucede, verifique si hay desbordamientos, errores fuera de
límite o mejore su algoritmo.

5. Aunque esto es raro en los concursos de programación modernos, no asuma que la entrada siempre
estará bien formateada si la descripción del problema no lo establece explícitamente (especialmente
para un problema mal escrito). Intente insertar espacios en blanco adicionales (espacios,
tabulaciones) en la entrada y pruebe si su código aún puede obtener los valores correctamente sin
fallar.

Sin embargo, después de seguir cuidadosamente todos estos pasos, aún puede obtener veredictos
que no sean de AC. En ICPC, usted (y su equipo) pueden considerar el veredicto del juez y la tabla de
líderes (generalmente disponible durante las primeras cuatro horas del concurso) para determinar su
próximo curso de acción. En IOI 2010-2012, los concursantes tienen un número limitado de tokens
para verificar la corrección de su código presentado contra los casos de prueba secretos. Con más
experiencia en tales concursos, podrá hacer mejores juicios y elecciones.

Ejercicio 1.2.4: Conciencia situacional


(principalmente aplicable en la configuración de ICPC; esto no es tan relevante en IOI).

1. Recibe un veredicto de WA por un problema muy fácil. ¿Qué debes hacer?

(a) Abandone este problema por otro.


(b) Mejorar el rendimiento de su solución (optimizaciones de código/mejor algoritmo).
(c) Cree casos de prueba complicados para encontrar el error.

(d) (En concursos por equipos): Pida a su compañero de equipo que rehaga el problema.

2. Recibe un veredicto de TLE para suO(norte3) solución. Sin


embargo, el máximonortees solo 100. ¿Qué debe hacer?

(a) Abandone este problema por otro.


(b) Mejorar el rendimiento de su solución (optimizaciones de código/mejor algoritmo).
(c) Cree casos de prueba complicados para encontrar el error.

3. Seguimiento a la Pregunta 2: ¿Qué pasa si el máximonortees 100.000?

4. Otro seguimiento de la Pregunta 2: ¿Qué pasa si el máximonortees 1.000, la salida solo depende del
tamaño de la entradanorte, y todavía tienescuatro horasde tiempo de competencia restante?

5. Recibe un veredicto de RTE. Su código (parece) ejecutarse perfectamente en su máquina.


¿Qué debes hacer?

14
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

6. Treinta minutos después del concurso, echas un vistazo a la tabla de líderes. Existen
muchos otros equipos que han resuelto un problemaXque su equipo no ha intentado.
¿Qué debes hacer?

7. A la mitad del concurso, echas un vistazo a la tabla de líderes. El equipo líder (suponga
que no es su equipo) acaba de resolver el problemaY.¿Qué debes hacer?

8. Su equipo ha dedicado dos horas a un problema desagradable. Has enviado varias implementaciones
por parte de diferentes miembros del equipo. Todas las presentaciones han sido juzgadas
incorrectas. No tienes idea de lo que está mal. ¿Qué debes hacer?

9. Queda una hora para el final del concurso. Tienes 1 código WA y 1 idea nueva para
otroproblema. ¿Qué debe hacer usted (o su equipo)?

(a) Abandone el problema con el código WA, cambie al otro problema en un intento
de resolver un problema más.
(b) Insista en que tiene que depurar el código WA. No hay suficiente tiempo para empezar a trabajar
en un nuevo problema.
(c) (En ICPC): Imprima el código WA. Pida a otros dos miembros del equipo que lo analicen mientras
usted cambia a ese otro problema en un intento de resolverlo.dosmas problemas.

1.2.6 Consejo 6: Práctica y más práctica


Los programadores competitivos, como los atletas reales, deben entrenar regularmente y mantenerse en forma.
Por lo tanto, en nuestro penúltimo consejo, proporcionamos una lista de varios sitios web con recursos que
pueden ayudarlo a mejorar su habilidad para resolver problemas. Creemos que el éxito es el resultado de un
esfuerzo continuo por mejorar.
El juez en línea de la Universidad de Valladolid (UVa, de España) [47] contiene problemas de concursos
anteriores de ACM (locales, regionales y hasta finales mundiales) además de problemas de otras fuentes,
incluidos varios problemas de concursos organizados por UVa. Puede resolver estos problemas y enviar sus
soluciones al juez en línea. La corrección de su programa será informada tan pronto como sea posible.
Intente resolver los problemas mencionados en este libro y es posible que algún día vea su nombre en la
lista de clasificación de los 500 mejores autores :-).
A partir del 24 de mayo de 2013, es necesario resolver≥542 problemas para estar en el top-500. Steven ocupa
el puesto 27 (por resolver 1674 problemas) mientras que Félix ocupa el puesto 37 (por resolver 1487 problemas)
de≈149008 usuarios de UVa (y un total de≈4097 problemas).
El juez en línea 'hermano' de UVa es ACM ICPC Live Archive [33] que contienecasi todos Conjuntos de
problemas recientes de ACM ICPC Regionals y World Final desde el año 2000. Entrena aquí si quieres tener
un buen desempeño en futuros ICPC. Tenga en cuenta que en octubre de 2011, aproximadamente cientos
de problemas de Live Archive (incluidos los enumerados en la segunda edición de este libro) se reflejaron en
UVa Online Judge.

Figura 1.2: Izquierda: Juez en línea de la Universidad de Valladolid; Derecha: ACM ICPC Live Archive.

15
1.3. PRIMEROS PASOS: LOS PROBLEMAS FÁCILES ©
c Steven y Félix

La Olimpiada de Computación de EE. UU. tiene un sitio web de capacitación muy útil [48] con concursos en línea
para ayudarlo a aprender habilidades de programación y resolución de problemas. Esto está más orientado a los
participantes del IIO que a los participantes del CIPC. Ve directo a su sitio web y entrena.
Sphere Online Judge [61] es otro juez en línea donde los usuarios calificados pueden agregar sus
problemas. Este juez en línea es bastante popular en países como Polonia, Brasil y Vietnam. Hemos utilizado
este SPOJ para publicar algunos de nuestros problemas de autoría propia.

Figura 1.3: Izquierda: USACO Training Gateway; Derecha: Juez en línea de Esfera

TopCoder organiza frecuentes 'Single Round Match' (SRM) [32] que consisten en algunos problemas que se resolverán en
1-2 horas. Después del concurso, se le da la oportunidad de 'desafiar' el código de otros concursantes proporcionando
casos de prueba complicados. Este juez en línea utiliza un sistema de calificación (codificadores rojos, amarillos, azules,
etc.) para recompensar a los concursantes que son realmente buenos en la resolución de problemas con una calificación
más alta en comparación con los concursantes más diligentes que resuelven una mayor cantidad de problemas más
fáciles.

1.2.7 Consejo 7: Trabajo en equipo (para ICPC)

Este último consejo no es algo fácil de enseñar, pero aquí hay algunas ideas que pueden valer la pena
probar para mejorar el rendimiento de su equipo:

• Practique la codificación en papel en blanco. (Esto es útil cuando su compañero de equipo está
usando la computadora. Cuando sea su turno de usar la computadora, puede escribir el código lo
más rápido posible en lugar de perder tiempo pensando frente a la computadora).

• La estrategia de 'enviar e imprimir': si su código obtiene un veredicto AC, ignore la impresión. Si


todavía no es AC, depure su código usando esa impresión (y deje que su compañero de equipo use la
computadora para otro problema). Cuidado: la depuración sin la computadora no es una habilidad
fácil de dominar.

• Si su compañero de equipo actualmente está codificando su algoritmo, prepare desafíos para su código
preparando datos de prueba de caso duro (esperemos que su código pase todos esos).

• El factor X: hazte amigo de tus compañeros de equipofuera dede entrenamientos y concursos.

1.3 Primeros pasos: los problemas fáciles


Nota: Puedes saltarte esta sección si eres un participante veterano de concursos de programación. Esta
sección está destinada a lectores que son nuevos en la programación competitiva.

1.3.1 Anatomía de un problema de concurso de programación


Un problema de concurso de programaciónnormalmentecontiene los siguientes componentes:

• Historia de fondo/descripción del problema. Por lo general, los problemas más fáciles se escriben
paraengañarconcursantes y hacer que parezca difícil, por ejemplo, agregando 'información adicional'
para crear una distracción. Los concursantes deben ser capaces defifiltrarestas

dieciséis
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

detalles sin importancia y centrarse en los esenciales. Por ejemplo, todos los párrafos iniciales
excepto la última oración en UVa 579 - ClockHands tratan sobre la historia del reloj y no tienen
ninguna relación con el problema real. Sin embargo, los problemas más difíciles generalmente
se escriben de la manera más sucinta posible: ya son lo suficientemente difíciles sin adornos
adicionales.

• Descripción de entrada y salida. En esta sección, se le darán detalles sobre cómo se formatea la
entrada y cómo debe formatear su salida. Esta parte generalmente se escribe de manera formal. Un
buen problema debe tener restricciones de entrada claras, ya que el mismo problema puede
resolverse con diferentes algoritmos para diferentes restricciones de entrada (consulte la Tabla 1.4).

• Muestra de entrada y muestra de salida. Los autores de problemas generalmente solo brindan
casos de prueba triviales a los concursantes. La entrada/salida de muestra está destinada a que los
concursantes verifiquen su comprensión básica del problema y verifiquen si su código puede analizar
la entrada dada usando el formato de entrada dado y producir la salida correcta usando el formato
de salida dado. No envíe su código al juez si ni siquiera pasa la entrada/salida de muestra dada.
Consulte la Sección 1.2.5 sobre cómo probar su código antes de enviarlo.

• Sugerencias o notas al pie. En algunos casos, los autores del problema pueden dejar sugerencias o agregar notas
al pie para describir el problema con más detalle.

1.3.2 Rutinas típicas de entrada/salida


Múltiples casos de prueba

En un problema de concurso de programación, la corrección de su código generalmente se determina ejecutando


su código contravariosCasos de prueba. En lugar de usar muchos archivos de casos de prueba individuales, los
problemas de concursos de programación modernos generalmente usanunaarchivo de caso de prueba con
múltiples casos de prueba incluidos. En esta sección, usamos un problema muy simple como ejemplo de un
problema de casos de prueba múltiple: dados dos enteros en una línea, imprima su suma en una línea.
Ilustraremos tres posibles formatos de entrada/salida:

• El número de casos de prueba se da en la primera línea de la entrada.

• Los casos de prueba múltiples terminan con valores especiales (generalmente ceros).

• Los casos de prueba múltiples terminan con la señal EOF (fin de archivo).

Código fuente C/C++ | Entrada de muestra | Salida de muestra


---------------------------------------------------------------------------------
int TC, a, b; |3 |3
escaneo("%d", &TC); // número de casos de prueba while
|12 | 12
(TC--) { // atajo para repetir hasta 0 | 5 7 |9
scanf("%d %d", &a, &b); // calcula la respuesta |63 |--------------
printf("%d\n", a + b); // sobre la marcha |--------------|
} | |
---------------------------------------------------------------------------------
int a, b; |12 |3
// detener cuando ambos enteros son 0 while |57 | 12
(scanf("%d %d", &a, &b), (a || b)) |63 |9
printf("%d\n", a + b); |00 |--------------

17
1.3. PRIMEROS PASOS: LOS PROBLEMAS FÁCILES ©
c Steven y Félix

---------------------------------------------------------------------------------
int a, b; |12 |3
// scanf devuelve el número de elementos |57 | 12
leídos while (scanf("%d %d", &a, &b) == 2) |63 |9
// o puede verificar EOF, es decir |--------------|-------------- |
// while (scanf("%d %d", &a, &b) != EOF) |
printf("%d\n", a + b); | |

Números de casos y líneas en blanco

Algunos problemas con múltiples casos de prueba requieren que la salida de cada caso de prueba se numere
secuencialmente. Algunos también requieren una línea en blancodespuéscada caso de prueba. Modifiquemos el
problema simple anterior para incluir el número de caso en la salida (a partir de uno) con este formato de salida: "
Caso [NÚMERO]: [RESPUESTA]”seguido de una línea en blanco para cada caso de prueba. Suponiendo que la
entrada termina con la señal EOF, podemos usar el siguiente código:

Código fuente C/C++ | Entrada de muestra | Salida de muestra


---------------------------------------------------------------------------------
int a, b, c = 1; |12 | Caso 1: 3
while (scanf("%d %d", &a, &b) != EOF) |57 |
// observe los dos '\n' printf("Caso %d: |63 | Caso 2: 12
%d\n\n", c++, a + b); |--------------|
| | Caso 39
| |
| |--------------

Algunos otros problemas requieren que generemos solo líneas en blancoEntreCasos de prueba. Si usamos el
enfoque anterior, terminaremos con una nueva línea adicional al final de nuestra salida, produciendo un veredicto
de 'Error de presentación' (PE) innecesario. Deberíamos usar el siguiente código en su lugar:

Código fuente C/C++ | Entrada de muestra | Salida de muestra


---------------------------------------------------------------------------------
int a, b, c = 1; |12 | Caso 1: 3
while (scanf("%d %d", &a, &b) != EOF) { |57 |
si (c > 1) printf("\n"); // 2do/más casos | 6 3 printf("Caso | Caso 2: 12
%d: %d\n", c++, a + b); |--------------|
} | | Caso 39
| |--------------

Número variable de entradas

Cambiemos un poco el problema simple de arriba. Para cada caso de prueba (cada línea de entrada), ahora
se nos da un número enterok(k≥1), seguido deknúmeros enteros Nuestra tarea ahora es generar la suma
de estosknúmeros enteros Suponiendo que la entrada termina con la señal EOF y no requerimos la
numeración de casos, podemos usar el siguiente código:

Código fuente C/C++ | Entrada de muestra | Salida de muestra


---------------------------------------------------------------------------------

18
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

int k, ans, v; |11 |1


while (scanf("%d", &k) != EOF) { |234 |7
respuesta = 0; |3811 | 10
while (k--) { scanf("%d", &v); respuesta += v; } | 4 7 2 9 3 | 21
printf("%d\n", respuesta); |511111 |5
} |--------------|--------------

Ejercicio 1.3.1*: ¿Qué pasa si el autor del problema decide hacer la entradaun poco más ¿problemático? En lugar
de un número enterokal comienzo de cada caso de prueba, ahora debe sumar todos los números enteros en cada
caso de prueba (cada línea). Sugerencia: Consulte la Sección 6.2.

Ejercicio 1.3.2*: ¡Reescriba todo el código fuente C/C++ en esta Sección 1.3.2 en Java!

1.3.3 Hora de iniciar el viaje


No hay mejor manera de comenzar tu viaje en la programación competitiva que resolver algunos
problemas de programación. Para ayudarle a elegir problemas para empezar entre los≈4097 en el
juez en línea UVa [47], a continuación enumeramos algunos de los problemas Ad Hoc más fáciles. Se
presentarán más detalles sobre los problemas Ad Hoc en la siguiente Sección 1.4.

• Muy facil
Deberías tener estos problemas AC9en menos de 7 minutos10¡cada! Si es nuevo en la
programación competitiva, le recomendamos que comience su viaje resolviendo algunos
problemas de esta categoría después de completar la Sección 1.3.2 anterior. Nota: dado que
cada categoría contiene numerosos problemas para que los pruebe, tenemosresaltadoun
máximo de tres (3)Deberías intentar *problemas de cada categoría. Estos son los problemas
que, a nuestro juicio, son más interesantes o de mayor calidad.

• Fácil
Hemos dividido la categoría 'Fácil' en dos más pequeñas. Los problemas en esta categoría
siguen siendo fáciles, pero solo 'un poco' más difíciles que los 'Súper fáciles'.

• Medio: una muesca por encima de fácil


Aquí, enumeramos algunos otros problemas Ad Hoc que pueden ser un poco más complicados (o más
largos) que los de la categoría 'Fácil'.

• Problemas superfáciles en el juez en línea de UVa (resueltos en menos de 7 minutos)

1. UVa 00272 - Comillas TEX (reemplace todas las comillas dobles por comillas de estilo TEX())

2.UVa 01124 - Peligro de celebridad(LA 2681, solo haga eco/reimprima la entrada nuevamente)

3. UVa 10550 - Candado de combinación (simple, haz lo que se te pida)

4. UVa 11044 - Buscando a Nessy (existe un código/fórmula de línea)


5.UVa 11172 - Operadores relacionales *(ad hoc, muy fácil, una línea)
6. UVa 11364 - Estacionamiento (escaneo lineal para obteneryo&r, respuesta = 2∗(r-l))
7.UVa 11498 - División de Nlogonia *(solo use declaraciones if-else)

9No te sientas mal si no puedes hacerlo. Puede haber muchas razones por las que un código no puede recibir AC.
10Siete minutos es solo una estimación aproximada. Algunos de estos problemas se pueden resolver con frases ingeniosas.

19
1.3. PRIMEROS PASOS: LOS PROBLEMAS FÁCILES ©
c Steven y Félix

8. UVa 11547 - Respuesta automática (una líneaO(1) la solución existe)


9.UVa 11727 - Reducción de costes *(ordenar los 3 números y obtener la mediana)
10. UVa 12250 - Detección de idioma (LA 4995, KualaLumpur10, verificación if-else)
11UVa 12279 - Equilibrio Emoogle(escaneo lineal simple)
12UVa 12289 - Uno-Dos-Tres(solo use declaraciones if-else)
13UVa 12372 - Embalaje para vacaciones(solo verifica si todolargo, ancho, alto≤20)
14UVa 12403 - Guardar configuración(directo)
15.UVa 12577 - Hayy-e-Akbar(directo)
• Fácil (solo 'un poco' más difícil que los 'Super Easy')
1. UVa 00621 - Investigación secreta (análisis de casos para solo 4 salidas posibles)
2.UVa 10114 - Comprador de automóvil a préstamo *(simplemente simule el proceso)
3. UVa 10300 - Prima Ecológica (ignorar número de animales)
4. UVa 10963 - The Swallowing Ground (para que dos bloques se puedan fusionar, los
espacios entre sus columnas deben ser iguales)
5. UVa 11332 - Suma de dígitos (recursiones simples)
6.UVa 11559 - Organización de eventos *(una pasada lineal)
7. UVa 11679 - Subprime (comprobar si después de la simulación todos los bancos tienen≥0 reserva)

8. UVa 11764 - Jumping Mario (un escaneo lineal para contar saltos altos y bajos)
9.UVa 11799 - Carrera de terror *(un escaneo lineal para encontrar el valor máximo)
10. UVa 11942 - Secuenciación de leñador (compruebe si la entrada está ordenada asc/descendente)

11. UVa 12015 - Google se siente afortunado (recorra la lista dos veces)
12UVa 12157 - Plan Tarifario(LA 4405, KualaLumpur08, calcular y comparar)
13UVa 12468 - Zapping(fácil; solo hay 4 posibilidades)
14UVa 12503 - Instrucciones del robot(simulación fácil)
15.UVa 12554 - Una canción especial...(simulación)
16. IOI 2010 - Cluedo (use 3 punteros)
17. IOI 2010 - Memoria (use 2 pases lineales)

• Medio: una muesca por encima de fácil (puede tomar de 15 a 30 minutos, pero no demasiado)

1. UVa 00119 - Regaladores codiciosos (simular el proceso de dar y recibir)


2.UVa 00573 - El Caracol *(simulación, ¡cuidado con los casos límite!)
3. UVa 00661 - Fusibles fundidos (simulación)
4.UVa 10141 - Solicitud de Propuesta *(solucionable con un escaneo lineal)
5. UVa 10324 - Ceros y Unos (simplifique usando una matriz 1D: cambie el contador)
6. UVa 10424 - Calculadora de amor (solo haz lo que se te pida)

7. UVa 10919 - ¿Requisitos previos? (procesar los requisitos a medida que se lee la entrada)
8.UVa 11507 - Bender B. Rodríguez...*(simulación, si no)
9. UVa 11586 - Vías del tren (TLE si es fuerza bruta, encuentre el patrón)
10. UVa 11661 - ¿Hora de la hamburguesa? (escaneo lineal)

11UVa 11683 - Escultura Láser(una pasada lineal es suficiente)


12. UVa 11687 - Dígitos (simulación; sencillo)
13. UVa 11956 - Brain**** (simulación; ignorar '.')
14UVa 12478 - Problema más difícil...(pruebe uno de los ocho nombres)
15. IOI 2009 - Garaje (simulación)
16. IOI 2009 - POI (ordenar)

20
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

1.4 Los problemas ad hoc


Terminaremos este capítulo discutiendo el primer tipo de problema adecuado en los ICPC y los IOI:
los problemas Ad Hoc. Según USACO [48], los problemas Ad Hoc son problemas que 'no se pueden
clasificar en ningún otro lugar' ya que cada descripción del problema y su correspondiente solución
son 'únicas'. Muchos problemas Ad Hoc son fáciles (como se muestra en la Sección 1.3), pero esto no
se aplica a todos los problemas Ad Hoc.
Los problemas ad hoc aparecen con frecuencia en los concursos de programación. En el CIPC,≈1-2 problemas
de cada≈10 problemas son problemas Ad Hoc. Si el problema Ad Hoc es fácil, normalmente será el primer
problema resuelto por los equipos en un concurso de programación. Sin embargo, hubo casos en los que las
soluciones a los problemas Ad Hoc eran demasiado complicadas de implementar, lo que provocó que algunos
equipos las postergaran estratégicamente hasta la última hora. En un concurso regional de ICPC con alrededor de
60 equipos, su equipo se clasificaría en la mitad inferior (puesto 30-60) si puedesolamente resolver problemas ad
hoc.
En IOI 2009 y 2010, ha habido 1 tarea fácil por día de competencia11, normalmente una tarea Ad
Hoc (Fácil). Si eres un concursante de IOI, definitivamente no ganarás ninguna medalla solo por
resolver las 2 tareas sencillas Ad Hoc durante los 2 días de competencia. Sin embargo, cuanto más
rápido pueda completar estas 2 tareas fáciles, más tiempo tendrá para trabajar en las otras 2×3 = 6
tareas desafiantes.
hemos enumeradomuchosProblemas Ad Hoc que hemos resuelto en el Juez Online de la UVa
[47] en las diversas categorías a continuación. Creemos que usted puede resolver la mayoría de estos problemas
sin queusando las estructuras de datos avanzadas o algoritmos que se discutirán en los capítulos posteriores.
Muchos de estos problemas Ad Hoc son 'simples' pero algunos de ellos pueden ser 'complicados'. Trate de
resolver algunos problemas de cada categoría antes de leer el siguiente capítulo.
Nota: una pequeña cantidad de problemas, aunque se enumeran como parte del Capítulo 1, pueden requerir
el conocimiento de los capítulos posteriores, por ejemplo, conocimiento de estructuras de datos lineales (matrices)
en la Sección 2.2, conocimiento de retroceso en la Sección 3.2, etc. Puede volver a revisar estos más difíciles.
Problemas ad hoc después de haber entendido los conceptos requeridos.

Las categorías:

• Carta de juego)
Hay muchos problemas Ad Hoc relacionados con juegos populares. Muchos están
relacionados con los juegos de cartas. Por lo general, necesitará analizar las cadenas de
entrada (consulte la Sección 6.3) ya que las cartas tienen ambos palos (D/Diamond/♦, C/
Club/♣, H/Corazón/♥, y S/Picas/♠) y rangos (generalmente: 2<3<. . .<9<T/Diez<J/Jack<Q/
Reina<K/Rey<A/A12). Puede ser una buena idea asignar estas cadenas problemáticas a
índices enteros. Por ejemplo, un mapeo posible es mapear D2→0, D3→1, . . . , AD→12, C2→
13, C3→14, . . . , SA→51. Entonces, puedes trabajar con los índices enteros.

• Juego (ajedrez)
El ajedrez es otro juego popular que a veces aparece en problemas de concursos de programación.
Algunos de estos problemas son ad hoc y se enumeran en esta sección. Algunos de ellos son
combinatorios con tareas como contar cuántas formas hay de colocar 8 reinas en 8×8 tablero de
ajedrez. Estos se enumeran en el Capítulo 3.

• Juego (Otros), más fácil y más difícil (o más tedioso)


Aparte de los juegos de cartas y ajedrez, muchos otros juegos populares se han abierto paso en los
concursos de programación: Tic Tac Toe, Piedra, Papel, Tijeras, Serpientes/Escaleras, BINGO,

11Esto ya no fue así en IOI 2011-2012, ya que las puntuaciones más fáciles están dentro de la subtarea 1 de cada tarea.
12En algunos otros arreglos, A/Ace<2.

21
1.4. LOS PROBLEMAS AD HOC ©
c Steven y Félix

Bolos, etc. Puede ser útil conocer los detalles de estos juegos, pero la mayoría de las reglas del
juego se dan en la descripción del problema para evitar perjudicar a los concursantes que no
están familiarizados con los juegos.

• Problemas relacionados conpalíndromos


Estos también son problemas clásicos. Un palíndromo es una palabra (o una secuencia) que se puede
leer de la misma manera en cualquier dirección. La estrategia más común para verificar si una
palabra es palindrómica es pasar del primer carácter almediouno y verifique si los caracteres
coinciden en la posición correspondiente desde atrás. Por ejemplo, 'ABCDCBA' es un palíndromo.
Para algunos problemas más difíciles relacionados con el palíndromo, puede consultar la Sección 6.5
para obtener soluciones de Programación Dinámica.

• Problemas relacionados conAnagramas


Esta es otra clase de problemas clásicos. Un anagrama es una palabra (o frase) cuyas letras se
pueden reordenar para obtener otra palabra (o frase). La estrategia común para verificar si dos
palabras son anagramas es ordenar las letras de las palabras y comparar los resultados. Por ejemplo,
tomepalabraA = 'taxi', palabraB = 'bca'.Después de clasificar,palabraA = 'abc'ypalabraB = 'abc'
también, por lo que son anagramas. Consulte la Sección 2.2 para conocer varias técnicas de
clasificación.

• InteresanteVida realProblemas, más fáciles y más difíciles (o más tediosos)


Esta es una de las categorías de problemas más interesantes del UVa Online Judge. Creemos que los
problemas de la vida real como estos son interesantes para aquellos que son nuevos en Ciencias de
la Computación. El hecho de que escribamos programas para resolver problemas de la vida real
puede ser un impulso de motivación adicional. Quién sabe, ¡es posible que obtenga información
nueva (e interesante) de la descripción del problema!

• Problemas ad hoc que implicanTiempo


Estos problemas utilizan conceptos de tiempo como fechas, horas y calendarios. Estos también son
problemas de la vida real. Como se mencionó anteriormente, estos problemas pueden ser un poco más
interesantes de resolver. Algunos de estos problemas serán mucho más fáciles de resolver si domina la
clase Java GregorianCalendar, ya que tiene muchas funciones de biblioteca que se ocupan del tiempo.

• 'Derrochador de tiempo'problemas
Estos son problemas Ad Hoc que están escritos específicamente para hacer que la solución requerida
sea larga y tediosa. Estos problemas, si aparecen en un concurso de programación, determinarían el
equipo con máseficientecodificador: alguien que puede implementar soluciones complicadas pero
aún precisas bajo limitaciones de tiempo. Los entrenadores deberían considerar agregar tales
problemas en sus programas de entrenamiento.

• Problemas ad hoc enotros capitulos


Hay muchos otros problemas Ad Hoc que hemos trasladado a otros capítulos ya que requerían
conocimientos por encima de las habilidades básicas de programación.

– Los problemas ad hoc que involucran el uso de estructuras de datos lineales básicas (especialmente
matrices) se enumeran en la Sección 2.2.

– Los problemas ad hoc que implican cálculos matemáticos se enumeran en la Sección 5.2.

– Los problemas ad hoc relacionados con el procesamiento de cadenas se enumeran en la Sección 6.3.

– Los problemas ad hoc que involucran geometría básica se enumeran en la Sección 7.2.

– Problemas ad hoc enumerados en el Capítulo 9.

22
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

Sugerencias: después de resolver una serie de problemas de programación, comienza a darse


cuenta de un patrón en sus soluciones. Ciertos modismos se usan con suficiente frecuencia en la
implementación de programación competitiva para que los atajos sean útiles. Desde una
perspectiva de C/C++, estos modismos pueden incluir: Bibliotecas que se incluirán (cstdio, cmath,
cstring, etc.), atajos de tipos de datos (ii, vii, vi,etc.), rutinas de E/S básicas (freopen, formato de
entrada múltiple, etc.), macros de bucle (por ejemplo, #define REP(i, a, b) para (int i = int(a); i <=
int(b); i++),etc.), y algunos otros. Un programador de la competencia que use C/C++ puede
almacenarlos en un archivo de encabezado como 'competitive.h'. Con tal encabezado, la solución a
cada problema comienza con un simple #incluir<competitivo.h>. Sin embargo, estos consejos no
deben usarse más allá de la programación competitiva, especialmente en la industria del software.

Ejercicios de Programación relacionados con problemas Ad Hoc:

• Carta de juego)

1. UVa 00162 - Beggar My Neighbor (simulación de juego de cartas; sencillo)


2.UVa 00462 - Evaluador de mano de puente *(simulación; tarjeta)
3. UVa 00555 - Bridge Hands (juego de cartas)
4. UVa 10205 - Stack 'em Up (juego de cartas)
5.UVa 10315 - Manos de Poker(problema tedioso)
6.UVa 10646 - ¿Qué es la Tarjeta? *(barajar cartas con alguna regla y luego
obtener cierta carta)
7. UVa 11225 - Puntuaciones de tarot (otro juego de cartas)
8. UVa 11678 - Intercambio de tarjeta (en realidad solo un problema de manipulación de matriz)
9.UVa 12247 - Jollo*(interesante juego de cartas; simple, pero requiere una buena lógica para que todos
los casos de prueba sean correctos)

• Juego (ajedrez)
1. UVa 00255 - Movimiento correcto (comprueba la validez de los movimientos de ajedrez)

2.UVa 00278 - Ajedrez *(ad hoc, ajedrez, fórmula de forma cerrada existe)
3.UVa 00696 - Cuantos Caballeros *(ad hoc, ajedrez)
4. UVa 10196 - Check The Check (juego de ajedrez ad hoc, tedioso)
5.UVa 10284 - Tablero de ajedrez en FEN *(FEN = La notación de Forsyth-Edwards es una
notación estándar para describir las posiciones del tablero en un juego de ajedrez)
6. UVa 10849 - Mover el alfil (ajedrez)
7. UVa 11494 - Reina (ad hoc, ajedrez)
• Juego (Otros), Más fácil
1. UVa 00340 - Sugerencias de Master-Mind (determinar coincidencias fuertes y débiles)
2.UVa 00489 - Juez del verdugo *(solo haz lo que se te pide)
3.UVa 00947 - Ayudante de mente maestra(similar a UVa 340)
4.UVa 10189 - Buscaminas *(simular Buscaminas, similar a UVa 10279)
5. UVa 10279 - Mine Sweeper (una matriz 2D ayuda, similar a UVa 10189)
6. UVa 10409 - Juego de dados (solo simula el movimiento del dado)
7. UVa 10530 - Juego de adivinanzas (use una matriz de banderas 1D)

8.UVa 11459 - Serpientes y escaleras *(simularlo, similar a UVa 647)


9.UVa 12239 - Bingo(probar los 902pares, ver si todos los números en [0..N]hay)

23
1.4. LOS PROBLEMAS AD HOC ©
c Steven y Félix

• Juego (Otros), Más difícil (más tedioso)


1. UVa 00114 - Simulation Wizardry (simulación de pinball)
2. UVa 00141 - The Spot Game (simulación, verificación de patrones)
3. UVa 00220 - Othello (sigue las reglas del juego, un poco tedioso)
4. UVa 00227 - Rompecabezas (analizar la entrada, manipulación de matrices)

5. UVa 00232 - Respuestas de crucigramas (problema complejo de manipulación de matrices)

6. UVa 00339 - Simulación de SameGame (siga la descripción del problema)


7. UVa 00379 - HI-Q (siga la descripción del problema)
8.UVa 00584 - Bolos *(simulación, juegos, comprensión lectora)
9. UVa 00647 - Chutes and Ladders (juego de mesa infantil, ver también UVa 11459)
10. UVa 10363 - Tic Tac Toe (comprobar la validez del juego Tic Tac Toe, complicado)
11UVa 10443 - Piedra, Tijera, Papel *(manipulación de matrices 2D)
12UVa 10813 - BINGO tradicional *(siga la descripción del problema)
13. UVa 10903 - Piedra, papel o tijera... (recuento de victorias+pérdidas, promedio de ganancias de salida)

• Palíndromo
1. UVa 00353 - Pesky Palindromes (fuerza bruta en todas las subcadenas)
2.UVa 00401 - Palíndromos *(control palíndromo simple)
3. UVa 10018 - Invertir y sumar (comprobación ad hoc, matemáticas, palíndromo)
4.UVa 10945 - Madre Osa *(palíndromo)
5.UVa 11221 - Palíndromo Cuadrado Mágico *(tratamos con una matriz)
6. UVa 11309 - Counting Chaos (verificación de palíndromo)
• Anagrama
1. UVa 00148 - Verificador de anagramas (usa retroceso)
2.UVa 00156 - Anagrama *(más fácil conalgoritmo::ordenar)
3.UVa 00195 - Anagrama *(más fácil conalgoritmo::siguiente permutación)
4.UVa 00454 - Anagramas *(anagrama)
5. UVa 00630 - Anagramas (II) (ad hoc, cadena)
6. UVa 00642 - Amalgama de palabras (revisar el pequeño diccionario dado para ver la
lista de posibles anagramas)
7. UVa 10098 - Generación rápida, clasificada... (muy similar a UVa 195)
• Interesantes problemas de la vida real, más fáciles

1.UVa 00161 - Semáforos *(esta es una situación típica en el camino)


2. UVa 00187 - Procesamiento de transacciones (un problema de contabilidad)
3. UVa 00362: 18 000 segundos restantes (situación típica de descarga de archivos)
4.UVa 00637 - Impresión de folletos *(aplicación en el software del controlador de la impresora)

5.UVa 00857 - Cuantificador(MIDI, aplicación en música por ordenador)


6. UVa 10082 - WERTYU (este error tipográfico nos pasa a veces)
7. UVa 10191 - Siesta más larga (es posible que desee aplicar esto a su propio horario)
8. UVa 10528 - Escalas mayores (el conocimiento musical está en la descripción del problema)
9. UVa 10554 - Calorías de grasa (¿le preocupa su peso?)
10UVa 10812 - Vence la propagación *(¡Tenga cuidado con los casos límite!)
11. UVa 11530 - Escritura de SMS (los usuarios de teléfonos móviles encuentran este problema todos los días)

12UVa 11945 - Gestión Financiera(un poco de formato de salida)


13. UVa 11984 - Un cambio en la unidad térmica (F◦a C◦conversión y viceversa)
14UVa 12195 - Composición de jingles(contar el número de compases correctos)
15.UVa 12555 - Bebé yo(una de las primeras preguntas que se hacen cuando nace un nuevo bebé;
requiere un poco de procesamiento de entrada)

24
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

• Problemas interesantes de la vida real, más difíciles (más tediosos)

1. UVa 00139 - Enredos telefónicos (calcular factura telefónica; manipulación de cadenas)


2. UVa 00145 - Gondwanaland Telecom (naturaleza similar con UVa 139)
3.UVa 00333 - Reconocimiento de buenos ISBN(nota: este problema tiene datos de prueba 'defectuosos'
con líneas en blanco que potencialmente causan muchos 'Errores de presentación')

4. UVa 00346 - Getting Chorded (acorde musical, mayor/menor)


5.UVa 00403 - Posdata *(emulación de controlador de impresora, tedioso)
6.UVa 00447 - Explosión demográfica(modelo de simulación de vida)
7. UVa 00448 - OOPS (conversión tediosa de 'hexadecimal' a 'lenguaje ensamblador')
8.UVa 00449 - Mención Escalas(más fácil si tienes formación musical)
9. UVa 00457 - Linear Cellular Automata (simulación simplificada del 'juego de la vida';
idea similar con UVa 447; explore Internet para ese término)
10. UVa 00538 - Saldo de cuentas bancarias (la premisa del problema es bastante cierta)
11UVa 00608 - Dólar Falsificado *(problema clásico)
12. UVa 00706 - Pantalla LC (lo que vemos en la pantalla digital antigua)
13UVa 01061 - Cálculos Consanguíneos *(LA 3736 - WorldFinals Tokyo07, consanguíneo =
sangre; este problema pregunta posibles combinaciones de tipos de sangre y factor Rh;
solucionable probando los ocho posibles tipos de sangre + Rh con
la información dada en la descripción del problema)
14. UVa 10415 - Eb Alto Saxofonista (sobre instrumentos musicales)
15. UVa 10659 - Ajuste de texto en diapositivas (los programas de presentación típicos hacen esto)

16. UVa 11223 - O: dah, dah, dah (tediosa conversión de código morse)
17. UVa 11743 - Verificación de crédito (algoritmo de Luhn para verificar números de tarjetas de crédito; busque en
Internet para obtener más información)

18UVa 12342 - Calculadora de impuestos(el cálculo de impuestos puede ser realmente complicado)

• Tiempo

1. UVa 00170 - Paciencia del reloj (simulación, tiempo)


2. UVa 00300 - Calendario Maya (ad hoc, tiempo)
3.UVa 00579 - Manecillas de reloj *(ad hoc, tiempo)
4.UVa 00893 - Y3K *(use Java GregorianCalendar; similar a UVa 11356)
5. UVa 10070 - Año bisiesto o no bisiesto... (más que los años bisiestos ordinarios)
6.UVa 10339 - Relojería(fiy la fórmula)
7. UVa 10371 - Zonas horarias (siga la descripción del problema)
8. UVa 10683 - El reloj decadario (conversión de sistema de reloj simple)
9. UVa 11219 - ¿Cuántos años tienes? (¡cuidado con los casos límite!)
10. UVa 11356 - Fechas (muy fácil si usa Java GregorianCalendar)
11. UVa 11650 - Reloj espejo (se requieren algunas matemáticas)
12. UVa 11677 - Despertador (idea similar con UVa 11650)
13UVa 11947 - Cáncer o Escorpio *(más fácil con Java GregorianCalendar)
14. UVa 11958 - Coming Home (cuidado con 'pasada la medianoche')
15. UVa 12019 - Algoritmo del Día del Juicio Final (calendario gregoriano; obtenga el DÍA DE LA SEMANA)

16. UVa 12136 - Horario de un hombre casado (LA 4202, Dhaka08, verifique la hora)
17UVa 12148 - Electricidad(fácil con el calendario gregoriano; use el método 'agregar'
para agregar un día a la fecha anterior y ver si es la misma que la fecha actual)
18UVa 12439 - 29 de febrero(exclusión inclusión; muchos casos de esquina; ten cuidado)
19UVa 12531 - Horas y Minutos(ángulos entre dos manecillas del reloj)

25
1.4. LOS PROBLEMAS AD HOC ©
c Steven y Félix

• 'Problemas de pérdida de tiempo

1. UVa 00144 - Becas para estudiantes (simulación)


2.UVa 00214 - Generación de código(simplemente simule el proceso; tenga
cuidado con restar (-), dividir (/) y negar (@), tedioso)
3. UVa 00335 - Procesamiento de registros MX (simulación)
4. UVa 00337 - Control de interpretación... (simulación, relacionada con la salida)

5. UVa 00349 - Voto Transferible (II) (simulación)


6. UVa 00381 - Haciendo el Grado (simulación)
7. UVa 00405 - Enrutamiento de mensajes (simulación)

8.UVa 00556 - Impresionante *(simulación)


9.UVa 00603 - Estacionamiento(simular el proceso requerido)
10UVa 00830 - Tiburón(muy difícil de conseguir AC, un error menor = WA)
11UVa 00945 - Cargando un buque de carga(simular el proceso de carga de carga dado)
12. UVa 10033 - Intérprete (adhoc, simulación)
13UVa 10134 - Pesca automática(hay que tener mucho cuidado con los detalles)

14. UVa 10142 - Votación australiana (simulación)


15. UVa 10188 - Guión de juez automatizado (simulación)
16. UVa 10267 - Editor gráfico (simulación)
17UVa 10961 - Persiguiendo a Don Giovanni(simulación tediosa)
18. UVa 11140 - El hermano pequeño de Little Ali (ad hoc)
19. UVa 11717 - Micro ahorro de energía... (simulación complicada)
20UVa 12060 - Promedio de todos los enteros *(LA 3012, Dhaka04, formato de salida)
21UVa 12085 - Móvil Casanova*(LA 2189, Dhaka06, cuidado con PE)
22UVa 12608 - Recogida de Basura(simulación con varios casos de esquina)

26
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

1.5 Soluciones a ejercicios sin estrella


Ejercicio 1.1.1: Un caso de prueba simple para romper algoritmos codiciosos esnorte=2, {(2,0),(2,1),(0,
0), (4,0)}. Un algoritmo codicioso emparejará incorrectamente{(2,0),(2,1)}y{(0,0),(4,0)}con un 5.000
costo mientras que la solución óptima es emparejar{(0,0),(2,0)}y{(2,1),(4,0)}con costo 4.236.

Ejercicio 1.1.2: Para una búsqueda completa ingenua como la que se describe en el cuerpo del texto, se necesitan
hastadieciséisC2×14C2× . . . ×2C2para el caso de prueba más grande connorte=8: demasiado grande. Sin embargo, hay
formas de reducir el espacio de búsqueda para que la búsqueda completa pueda seguir funcionando. Para un
desafío adicional, intenteEjercicio 1.1.3*!

Ejercicio 1.2.1: A continuación se muestra la Tabla 1.3 completa.

UVa Título Tipo de problema Insinuación

10360 ataque de rata Búsqueda completa o DP Sección 3.2


10341 Resuélvelo Divide & Conquer (método de Sección 3.3
11292 Dragón de Loowater bisección) Greedy (no clásico) Sección 3.4
11450 Compras para bodas DP (No Clásica) Sección 3.5
10911 Formación de equipos de prueba DP con máscaras de bits (No clásica) Gráfico Sección 8.3.1
11635 Reserva de hotel (Descomposición: Dijkstra's + BFS) Gráfico Sección 8.4
11506 programador enojado (Min Cut/Max Flow) Sección 4.6
10243 ¡Fuego! ¡¡Fuego!! ¡¡¡Fuego!!! Descomposición de DP en árbol (cobertura mínima de Sección 4.7.1
10717 menta vértice): búsqueda completa + cadena matemática Sección 8.4
11512 GATTACA (matriz de sufijos, LCP, LRS) Sección 6.6
10065 Empacadores de mosaicos inútiles Geometría (casco convexo + área de polígono) Sección 7.3.7

Ejercicio 1.2.2: Las respuestas son:

1. (b) Use una estructura de datos de cola de prioridad (montón) (Sección 2.3).

2. (b) Use Consulta de suma de rango 2D (Sección 3.5.2).

3. Si la lista L es estática, (b) matriz simple que se procesa previamente con programación dinámica
(sección 2.2 y 3.5). Si la lista L es dinámica, entonces (g) Fenwick Tree es una mejor respuesta (más
fácil de implementar que (f) Segment Tree).

4. (a) Sí, es posible realizar una búsqueda completa (Sección 3.2).

5. (a)O(V+mi) Programación dinámica (Sección 3.5, 4.2.5 y 4.7.1).


Sin embargo, (c)O((V+mi) Iniciar sesiónV)El algoritmo de Dijkstra también es posible ya que el extra O(Iniciar sesión
V)el factor sigue siendo "pequeño" paraVhasta 100k.

6. (a) Tamiz de Eratóstenes (Sección 5.5.1).

7. (b) El enfoque ingenuo anterior no funcionará. Debemos (primar) factorizarnorte! ymetroy ver si
los factores (primos) demetrose encuentra en los factores denorte! (Sección 5.5.5).

8. (b) No, debemos encontrar otra manera. Primero, encuentre el casco convexo delnortepuntos en O(norte
Iniciar sesiónnorte) (Sección 7.3.7). Sea el número de puntos enCH(S) =k. Como los puntos están dispersos
al azar,kserá mucho más pequeño quenorte. Luego, encuentre los dos puntos más lejanos examinando
todos los pares de puntos en elCH(S) enO(k2).

9. (b) El enfoque ingenuo es demasiado lento. ¡Utilice KMP o matriz de sufijos (Sección 6.4 o 6.6)!

27
1.5. SOLUCIONES A EJERCICIOS SIN ESTRELLA ©
c Steven y Félix

Ejercicio 1.2.3: El código Java se muestra a continuación:

// Código Java para la tarea 1, suponiendo que se hayan realizado todas las importaciones
necesarias class Main {
public static void main(String[] args) {
Escáner sc = nuevo Escáner (System.in);
doble d = sc.nextDouble();
Sistema.salida.printf("%7.3f\n", d); // ¡sí, Java también tiene printf!
}}

// Código C++ para la tarea 2, suponiendo que se hayan realizado todas las inclusiones necesarias
int main() {
doble pi = 2 * acos(0.0); int n; // esta es una forma más precisa de calcular pi
escaneo("%d", &n);
printf("%.*lf\n", n, pi); // esta es la forma de manipular el ancho del campo
}

// Código Java para la tarea 3, suponiendo que se hayan realizado todas las importaciones
necesarias class Main {
public static void main(String[] args) {
Cadena[] nombres = nueva Cadena[]
{ "", "Dom LUN Mar MIE JUE VIE SAB" };
Calendario calendar = new GregorianCalendar(2010, 7, 9); // 9 de agosto de 2010
// tenga en cuenta que el mes comienza desde 0, por lo que debemos poner 7 en lugar
de 8 System.out.println(names[calendar.get(Calendar.DAY_OF_WEEK)]); // "Casarse"
}}

// Código C++ para la tarea 4, suponiendo que se hayan realizado todas las inclusiones necesarias
# definir TODO(x) x.begin(), x.end()
# define ÚNICO(c) (c).cambiar tamaño(único(TODOS(c)) - (c).begin())

int principal() {
int a[] = {1, 2, 2, 2, 3, 3, 2, 2, 1}; vector<int>
v(a, a + 9);
ordenar (TODO (v)); ÚNICO(v);
for (int i = 0; i < (int)v.size(); i++) printf("%d\n", v[i]);
}

// Código C++ para la tarea 5, suponiendo que se hayan realizado todas las inclusiones
necesarias typedef pair<int, int> ii; // utilizaremos el orden de clasificación natural //
par typedef<int, ii> iii; de los tipos de datos primitivos que emparejamos

int principal() {
iii A = hacer_par(ii(5, 24), -1982); iii B = // reordenar DD/MM/AAAA
hacer_par(ii(5, 24), -1980); iii C = // a MM, DD,
hacer_par(ii(11, 13), -1983); vector<iii> // y luego usa YYYY NEGATIVO
cumpleaños;
cumpleaños.push_back(A); cumpleaños.push_back(B); cumpleaños.push_back(C);
sort(cumpleaños.begin(), cumpleaños.end()); // eso es todo :)
}

28
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

// Código C++ para la tarea 6, suponiendo que se hayan realizado todas las inclusiones necesarias
int main() {
int n = 5, L[] = {10, 7, 5, 20, 8}, v = 7; ordenar(L, L
+ n);
printf("%d\n", binary_search(L, L + n, v));
}

// Código C++ para la tarea 7, suponiendo que se hayan realizado todas las inclusiones necesarias
int main() {
intp[10], N = 10; para (int i = 0; i < N; i++) p[i] = i; hacer {

for (int i = 0; i < N; i++) printf("%c ", 'A' + p[i]); imprimirf("\n");

}
while (siguiente_permutación(p, p + N));
}

// Código C++ para la tarea 8, suponiendo que se hayan realizado todas las inclusiones necesarias
int main() {
intp[20], N = 20;
para (int i = 0; i < N; i++) p[i] = i; para (int i =
0; i < (1 << N); i++) {
para (int j = 0; j < N; j++)
si (i & (1 << j)) // si el bit j está activado //
printf("%d", p[j]); esto es parte del conjunto
imprimirf("\n");
}}

// Código Java para la tarea 9, suponiendo que se hayan realizado todas las importaciones
necesarias class Main {
public static void main(String[] args) {
Cadena cadena = "FF"; entero X = 16, Y = 10;
System.out.println(nuevo BigInteger(str, X).toString(Y));
}}

// Código Java para la tarea 10, suponiendo que se hayan realizado todas las importaciones
necesarias class Main {
public static void main(String[] args) {
String S = "línea: a70 y z72 serán reemplazadas, aa24 y a872 no";
System.out.println(S.replaceAll("(^| )+[az][0-9][0-9]( |$)+", " *** "));
}}

// Código Java para la tarea 11, suponiendo que se hayan realizado todas las importaciones
necesarias class Main {
public static void main(String[] args) lanza Exception {
ScriptEngineManager mgr = nuevo ScriptEngineManager();
Motor ScriptEngine = mgr.getEngineByName("JavaScript"); // "hacer trampa"

Escáner sc = nuevo Escáner (System.in);


while (sc.hasNextLine()) System.out.println(engine.eval(sc.nextLine()));
}}

29
1.5. SOLUCIONES A EJERCICIOS SIN ESTRELLA ©
c Steven y Félix

Ejercicio 1.2.4: Las consideraciones situacionales están entre paréntesis:

1. Recibe un veredicto de WA por un problema muy fácil. ¿Qué debes hacer?

(a) Abandone este problema por otro.(No está bien, tu equipo perderá).
(b) Mejore el rendimiento de su solución.(Inútil.)
(c) Cree casos de prueba complicados para encontrar el error.(La respuesta más lógica.)
(d) (En concursos por equipos): Pida a su compañero de equipo que rehaga el problema.(Esto
podría ser factible ya que es posible que haya tenido algunas suposiciones incorrectas
sobre el problema. Por lo tanto, debe abstenerse de contarle los detalles del problema a
su compañero de equipo, quien volverá a resolver el problema. Aún así, su equipo perderá
un tiempo precioso).

2. Recibe un veredicto de TLE para suO(norte3) solución. Sin


embargo, el máximonortees solo 100. ¿Qué debe hacer?

(a) Abandone este problema por otro.(No está bien, tu equipo perderá).
(b) Mejore el rendimiento de su solución.(No está bien, no deberíamos obtener TLE con
unO(norte3)algoritmo sinorte≤400.)
(c) Cree casos de prueba complicados para encontrar el error.(Esta es la respuesta: tal vez su programa
se encuentre con un bucle infinito accidental en algunos casos de prueba).

3. Seguimiento a la Pregunta 2: ¿Qué pasa si el máximonortees 100.000?


(Sinorte >400, es posible que no tenga más remedio que mejorar el rendimiento del
algoritmo actual o utilizar otro algoritmo más rápido).

4. Otro seguimiento de la Pregunta 2: ¿Qué pasa si el máximonortees 1.000, la salida solo depende del
tamaño de la entradanorte, y todavía tienescuatro horasde tiempo de competencia restante? (Si la
salida solo depende denorte, túmayoser capaz de calcular previamente todas las soluciones
posibles ejecutando suO(norte3)algoritmo en segundo plano, permitiendo que su compañero de
equipo use la computadora primero. Una vez que suO(norte3)solución termina, usted tiene
todas las respuestas. Enviar elO(1)responda en su lugar si no excede el 'límite de tamaño del
código fuente' impuesto por el juez).

5. Recibe un veredicto de RTE. Su código (parece) ejecutarse perfectamente en su máquina.


¿Qué debes hacer?
(Las causas más comunes de RTE suelen ser tamaños de matriz que son demasiado pequeños o
errores de recursividad infinita/desbordamiento de pila. Diseñe casos de prueba que puedan
desencadenar estos errores en su código).

6. Treinta minutos después del concurso, echas un vistazo a la tabla de líderes. Existen
muchos otros equipos que han resuelto un problemaXque su equipo no ha intentado.
¿Qué debes hacer?
(Un miembro del equipo debe intentar resolver el problema de inmediato).Xya que puede ser
relativamente fácil. Tal situación es realmente una mala noticia para su equipo, ya que es un revés
importante para obtener una buena clasificación en el concurso).

7. A la mitad del concurso, echas un vistazo a la tabla de líderes. El equipo líder (suponga que
no es su equipo) acaba de resolver el problemaY.¿Qué debes hacer? (Si su equipo no es el
que 'marca el ritmo', entonces es una buena idea 'ignorar' lo que está haciendo el
equipo líder y concentrarse en resolver los problemas que su equipo ha identificado
como 'solubles'. concurso, su equipo debe haber leído todos los problemas en el
conjunto de problemas e identificado aproximadamente los problemas que se
pueden resolver con las habilidades actuales de su equipo).

30
CAPÍTULO 1 INTRODUCCIÓN ©
c Steven y Félix

8. Su equipo ha dedicado dos horas a un problema desagradable. Has enviado varias implementaciones
por parte de diferentes miembros del equipo. Todas las presentaciones han sido juzgadas
incorrectas. No tienes idea de lo que está mal. ¿Qué debes hacer?
(Es hora de dejar de resolver este problema. No acapare la computadora, deje que su
compañero de equipo resuelva otro problema. O su equipo realmente no entendió el
problema o, en un caso muy raro, la solución del juez es realmente incorrecta. En
cualquier caso , esta no es una buena situación para su equipo).

9. Queda una hora para el final del concurso. Tienes 1 código WA y 1 idea nueva paraotro
problema. ¿Qué debe hacer usted (o su equipo)? (En la terminología del ajedrez, esto se
llama la situación de 'final del juego').

(a) Abandone el problema con el código WA, cambie al otro problema en un intento de
resolver un problema más.(Está bien en concursos individuales como IOI).
(b) Insista en que tiene que depurar el código WA. No hay suficiente tiempo para empezar
a trabajar en un nuevo problema.(Si la idea de otro problema implica un código
complejo y tedioso, entonces decidir centrarse en el código WA puede ser una
buena idea en lugar de tener dos soluciones incompletas/'no AC').
(c) (En ICPC): Imprima el código WA. Pida a otros dos miembros del equipo que lo analicen
mientras usted cambia a ese otro problema en un intento de resolverlo.dosmas
problemas. (Si la solución para el otro problema se puede codificar en menos de 30
minutos, impleméntela mientras sus compañeros de equipo intentan encontrar el
error del código WA estudiando la copia impresa).

Figura 1.4: Algunas referencias que inspiraron a los autores a escribir este libro

31
1.6. NOTAS DEL CAPÍTULO ©
c Steven y Félix

1.6 Notas del capítulo


Este capítulo, así como los capítulos subsiguientes, están respaldados por muchos libros de texto (consulte la
Figura 1.4 en la página anterior) y recursos de Internet. Aquí hay algunas referencias adicionales:

• Para mejorar su habilidad de mecanografía como se menciona en el Consejo 1, es posible que desee jugar a los muchos juegos de

mecanografía disponibles en línea.

• El consejo 2 está adaptado del texto de introducción en el portal de capacitación de USACO [48].

• Se pueden encontrar más detalles sobre el Consejo 3 en muchos libros de CS, por ejemplo, Capítulo 1-5, 17 de [7].

• Referencias en línea para el Consejo 4:


http://www.cppreference.comyhttp://www.sgi.com/tech/stl/para C++ STL; http://
docs.oracle.com/javase/7/docs/api/para la API de Java.
No tiene que memorizar todas las funciones de la biblioteca, pero es útil para memorizar las funciones que
utiliza con frecuencia.

• Para obtener más información sobre mejores pruebas (Consejo 5), puede valer la pena intentar un pequeño desvío a los
libros de ingeniería de software.

• Hay muchos otros Jueces en línea además de los mencionados en el Consejo 6, p.

– fuerzas de código,http://codeforces.com/,
– Juez en línea de la Universidad de Pekín, (POJ)http://poj.org,
– Juez en línea de la Universidad de Zhejiang, (ZOJ)http://acm.zju.edu.cn,
– Juez en línea de la Universidad de Tianjin,http://acm.tju.edu.cn/toj,
– Juez en línea de la Universidad Estatal de los Urales (Timus),http://acm.timus.ru,
– Juez en línea URI,http://www.urionlinejudge.edu.br,etc.

• Para obtener una nota sobre la competencia por equipos (Consejo 7), lea [16].

En este capítulo, le hemos presentado el mundo de la programación competitiva. Sin embargo,


un programador competitivo debe ser capaz de resolver más que problemas Ad Hoc en un
concurso de programación. Esperamos que disfrute el viaje y alimente su entusiasmo leyendo y
aprendiendo nuevos conceptos en elotrocapítulos de este libro. Una vez que haya terminado de
leer el libro, vuelva a leerlo una vez más. En la segunda vez, intente y resuelva el ≈238 ejercicios
escritos y el≈1675 ejercicios de programación.

Estadísticas Primera edición Segunda edicion Tercera edicion


Número de páginas 13 19 (+46%) 32 (+68%)
Ejercicios escritos 4 4 6+3*=9 (+125%)
Ejercicios de programación 34 160 (+371%) 173 (+8%)

32
Capitulo 2

Estructuras de datos y bibliotecas

Si he visto más allá, es solo subido a hombros de gigantes.


—Isaac Newton

2.1 Resumen y motivación


Una estructura de datos (DS) es un medio para almacenar y organizar datos. Diferentes
estructuras de datos tienen diferentes fortalezas. Por lo tanto, al diseñar un algoritmo,
es importante elegir uno que permita inserciones, búsquedas, eliminaciones, consultas
y/o actualizaciones eficientes, según lo que necesite su algoritmo. Aunque una
estructura de datos en sí misma no resuelve un problema (concurso de programación)
(el algoritmo que opera en ella sí lo hace), usar una estructura de datos
apropiadamente eficiente para un problema puede ser la diferencia entre pasar o
exceder el límite de tiempo del problema. Puede haber muchas formas de organizar los
mismos datos y, a veces, una forma es mejor que la otra en algunos contextos.
Ilustraremos esto varias veces en este capítulo.
Como se indica en el prefacio de este libro,asumireso eresfamiliarcon las estructuras de datos
básicos enumerados en la Sección 2.2-2.3 y por lo tanto vamos anorepásalas en este libro. En su
lugar, simplemente destacaremos el hecho de que existen implementaciones integradas para estas
estructuras de datos elementales en C++ STL y Java API.1. Si cree que no está completamente
familiarizado con alguno de los términos o estructuras de datos mencionados en la Sección 2.2-2.3,
revise esos términos y conceptos particulares en los diversos libros de referencia.2que los cubren,
incluyendo clásicos como “Introducción a los algoritmos” [7], “Abstracción de datos y resolución de
problemas” [5, 54], “Estructuras de datos y algoritmos” [12], etc. Continúe leyendo este libro solo
cuando entender al menos elconceptos básicosdetrás de estas estructuras de datos.
Tenga en cuenta que para la programación competitiva, solo necesita saber lo suficiente sobre estas
estructuras de datos para poder seleccionar yusarlas estructuras de datos correctas para cada problema de
concurso dado. Debe comprender las fortalezas, las debilidades y las complejidades de tiempo/espacio de las
estructuras de datos típicas. La teoría detrás de ellos es definitivamente una buena lectura, pero a menudo se
puede omitir o hojear, ya que las bibliotecas integradas proporcionan implementaciones listas para usar y
altamente confiables de estructuras de datos que de otro modo serían complejas. Esto esnouna buena práctica,
pero encontrará que a menudo es suficiente. Muchos concursantes (más jóvenes) han podido utilizar el eficiente
(con unO(Iniciar sesiónnorte) complejidad para la mayoría de las operaciones) C++ STLmapa (o

1Incluso en esta tercera edición,todavíautiliza principalmente código C++ para ilustrar técnicas de implementación. Los
equivalentes de Java se pueden encontrar en el sitio web de apoyo de este libro.
2Los materiales en la Sección 2.2-2.3 generalmente se cubren en el primer añoEstructuras de datoscurrículos de CS. Se alienta a
los estudiantes de secundaria que aspiran a participar en el IOI a participar en el estudio independiente de dicho material.

33
2.1. VISIÓN GENERAL Y MOTIVACIÓN ©
c Steven y Félix

JavaÁrbolMapa)implementaciones para almacenar colecciones dinámicas de pares clave-datos sin comprender que
la estructura de datos subyacente es unÁrbol de búsqueda binario balanceado, o use el STL de C++cola de
prioridad (o Javacola de prioridad)ordenar una cola de elementos sin comprender que la estructura de datos
subyacente es un(generalmente Binario) Montón. Ambas estructuras de datos generalmente se enseñan en los
planes de estudio de Ciencias de la Computación del primer año.
Este capitulo esta dividido en tres partes. La sección 2.2 contiene información básicalinealestructuras de
datos y las operaciones básicas que soportan. Sección 2.3 cubre básicono linealestructuras de datos tales
como árboles de búsqueda binarios (BST) (equilibrados), montones (binarios) y tablas hash, así como sus
operaciones básicas. La discusión de cada estructura de datos en la Sección 2.2-2.3 es breve, con énfasis en
la importanterutinas de la bibliotecaque existen para manipular las estructuras de datos. Sin embargo, las
estructuras de datos especiales que son comunes en los concursos de programación, como la máscara de
bits y varias técnicas de manipulación de bits (vea la figura 2.1), se analizan con más detalle. La Sección 2.4
contienemásestructuras de datos para las que no existe una implementación incorporada y, por lo tanto,
requieren que construyamosnuestra propiabibliotecas La Sección 2.4 tiene una discusión más profunda que
la Sección 2.2-2.3.

Características de valor agregado de este libro

Como este capítulo es el primero que se sumerge en el corazón de la programación competitiva, ahora
aprovecharemos la oportunidad para resaltar varias características de valor agregado de este libro que verá
en este capítulo y en los siguientes.
Una característica clave de este libro es la colección que lo acompaña deejemplos eficientes y
completamente implementadostanto en C/C++ como en Java del que carecen muchos otros libros de
Ciencias de la Computación, deteniéndose en el 'nivel de pseudocódigo' en su demostración de estructuras
de datos y algoritmos. Esta característica ha estado en el libro desde la primera edición. Las partes
importantes del código fuente se han incluido en el libro.3y el código fuente completo está alojado en
sites.google.com/site/stevenhalim/home/material.La referencia a cada archivo de origen se indica en el
cuerpo del texto como un cuadro como el que se muestra a continuación.

Código fuente:chx yy nombre.cpp/java

Otro punto fuerte de este libro es la colección de ejercicios escritos y de programación (en su mayoría
respaldados por UVa Online Judge [47] e integrados con uHunt; consulte el Apéndice A). En elterceraedición,
hemos añadidomucho masejercicios escritos. Hemos clasificado los ejercicios escritos ensin estrellay
sembrado de estrellasunos. Los ejercicios escritos sin asterisco están destinados a ser utilizados
principalmente con fines de autoevaluación; Las soluciones se dan al final de cada capítulo. Los ejercicios
escritos con estrellas se pueden usar para desafíos adicionales; no proporcionamos soluciones para estos,
pero en su lugar podemos proporcionar algunos consejos útiles.
En elterceraedición, hemos agregado visualizaciones4para muchas estructuras de datos y algoritmos
cubiertos en este libro [27]. Creemos que estas visualizaciones serán de gran beneficio para los estudiantes
visuales en nuestra base de lectores. En este momento (24 de mayo de 2013), las visualizaciones están
alojadas en:www.comp.nus.edu.sg/∼stevenha/visualización.La referencia a cada visualización se incluye en
el cuerpo del texto como un cuadro como el que se muestra a continuación.

Visualización:www.comp.nus.edu.sg/∼stevenha/visualización

3Sin embargo, hemos optado por no incluir el código de la Sección 2.2-2.3 en el cuerpo del texto porque en su mayoría
son 'triviales' para muchos lectores, excepto quizás por algunos trucos útiles.
4Están construidos con lienzo HTML5 y tecnología JavaScript.

34
CAPÍTULO 2. ESTRUCTURAS DE DATOS Y BIBLIOTECAS ©
c Steven y Félix

2.2 DS lineal con bibliotecas integradas


Una estructura de datos se clasifica comolinealestructura de datos si sus elementos forman una secuencia lineal, es decir,
sus elementos están dispuestos de izquierda a derecha (o de arriba a abajo). El dominio de estas estructuras básicas de
datos lineales a continuación es fundamental en los concursos de programación de hoy.

• Static Array (soporte nativo tanto en C/C++ como en Java)


Esta es claramente la estructura de datos más utilizada en los concursos de programación. Siempre que
haya una colección de datos secuenciales para ser almacenados y posteriormente accedidos usando su
índices, la matriz estática es la estructura de datos más natural para usar. Como el tamaño de entrada
máximo se suele mencionar en la declaración del problema, el tamaño de la matriz puede declararse como
el tamaño de entrada máximo, con un pequeño búfer adicional (centinela) por seguridad, para evitar el RTE
innecesario. Por lo general, las matrices 1D, 2D y 3D se utilizan en concursos de programación; los
problemas rara vez requieren matrices de mayor dimensión. Las operaciones de matriz típicas incluyen el
acceso a elementos por sus índices, la clasificación de elementos, la realización de un escaneo lineal o una
búsqueda binaria en una matriz ordenada.

• Matriz redimensionable dinámicamente: C++ STLvectores (JavaLista de arreglo (más rápido) oVector)
Esta estructura de datos es similar a la matriz estática, excepto que está diseñada para manejar el
cambio de tamaño en tiempo de ejecución de forma nativa. Es mejor usar unvectoren lugar de una
matriz si se desconoce el tamaño de la secuencia de elementos en tiempo de compilación. Por lo
general, inicializamos el tamaño (reserva()oredimensionar())con el tamaño estimado de la colección
para un mejor rendimiento. STL típico de C++vectorLas operaciones utilizadas en la programación
competitiva incluyen retroceder(), en(),el operador,asignar(), borrar(), borrar(),yiteradors para
atravesar el contenido devectors.

Código fuente:vector de matriz ch2 01.cpp/java

Es apropiado discutir dos operaciones comúnmente realizadas en Arrays:Clasificación y


buscando. Estas dos operaciones están bien soportadas en C++ y Java.
Existenmuchosalgoritmos de clasificación mencionados en los libros de CS [7, 5, 54, 12, 40, 58], por ejemplo

1.O(norte2) algoritmos de ordenación basados en comparación: Burbuja/Selección/Ordenación por inserción,


etc. Estos algoritmos son (terriblemente) lentos y generalmente se evitan en los concursos de
programación, aunque comprenderlos podría ayudarlo a resolver ciertos problemas.

2.O(norteIniciar sesiónnorte) algoritmos de clasificación basados en comparación: Merge/Heap/Quick Sort, etc.


Estos algoritmos son la opción predeterminada en los concursos de programación como unO(norteIniciar
sesiónnorte) la complejidad es óptima para la clasificación basada en la comparación. Por lo tanto, estos
algoritmos de clasificación se ejecutan en el "mejor tiempo posible" en la mayoría de los casos (consulte a
continuación los algoritmos de clasificación de propósito especial). Además, estos algoritmos son bien
conocidos y, por lo tanto, no necesitamos 'reinventar la rueda'5—podemos simplemente usarclasificación,
clasificación parcial,o tipo estableen C++ STLalgoritmo (oColecciones.clasificaren Java) para tareas de
clasificación estándar. Solo necesitamos especificar la función de comparación requerida y estas rutinas de
biblioteca se encargarán del resto.

3. Algoritmos de clasificación de propósito especial:O(norte) Counting/Radix/Bucket Sort, etc. Aunque


rara vez se usan, es bueno conocer estos algoritmos de propósito especial, ya que pueden reducir el
tiempo de clasificación requerido si los datos tienen ciertas características especiales. Por ejemplo,
Counting Sort se puede aplicar a datos enteros que se encuentran en un rango pequeño (consulte la
Sección 9.32).

5Sin embargo, a veces necesitamos 'reinventar la rueda' para ciertos problemas relacionados con la clasificación, por ejemplo, el
problema del Índice de Inversión en la Sección 9.14.

35
2.2. DS LINEAL CON BIBLIOTECAS INTEGRADAS ©
c Steven y Félix

En general, existen tres métodos comunes para buscar un elemento en una matriz:

1.O(norte) Búsqueda lineal: considere todos los elementos desde el índice 0 hasta el índicenorte -1 (evítelo
siempre que sea posible).

2.O(Iniciar sesiónnorte) Búsqueda binaria: Usolímite inferior, límite superior,obúsqueda binariaen C++
STLalgoritmo (o JavaColecciones.binarySearch).Si la matriz de entrada no está ordenada, es necesario
ordenar la matriz al menos una vez (utilizando uno de losO(norteIniciar sesiónnorte) algoritmo de
clasificación anterior) antes de ejecutar uno (omuchos) Búsqueda(s) binaria(s).

3.O(1) con Hashing: esta es una técnica útil para usar cuando se requiere un acceso rápido a valores
conocidos. Si se selecciona una función hash adecuada, la probabilidad de que se produzca una
colisión es insignificantemente pequeña. Aún así, esta técnica rara vez se usa y podemos vivir sin ella.
6para la mayoría de los problemas (de concurso).

Visualización:www.comp.nus.edu.sg/∼stevenha/visualización/clasificación.html
Código fuente:ch2 02 algoritmo colecciones.cpp/java

• Matriz de booleanos: C++ STLconjunto de bits (Javaconjunto de bits)

Si nuestra matriz solo necesita contener valores booleanos (1/verdadero y 0/falso), podemos usar una
estructura de datos alternativa que no sea una matriz: un C++ STLconjunto de bitslosconjunto de bits
soporta operaciones útiles comorestablecer(), establecer(),el operador [] yprueba().

Código fuente:ch5 06 primos.cpp/java,ver también la Sección 5.5.1

• Máscaras de bits, también conocidas como conjuntos ligeros y pequeños de booleanos (soporte nativo en C/C++/
Java) Un número entero se almacena en la memoria de una computadora como una secuencia/cadena de bits. Por
lo tanto, podemos usar números enteros para representar unligeropequeño conjunto de valores booleanos. Todas
las operaciones de conjunto involucran solo la manipulación bit a bit del entero correspondiente, lo que lo
convierte en unmucho más eficienteelección en comparación con C++ STLvector<bool>, conjunto de bits,o
establecer<En t>opciones Tal velocidad es importante en la programación competitiva. AlgunoLas operaciones
importantes que se utilizan en este libro se muestran a continuación.

Figura 2.1: Visualización de máscara de bits

1. Representación: 32 (o 64) bitsfirmadoentero para hasta 32 (o 64) elementos7. Sin pérdida de


generalidad, todos los ejemplos a continuación usan un entero con signo de 32 bits llamadoS.

6Sin embargo, las preguntas sobre hash aparecen con frecuencia en las entrevistas para trabajos de TI.
7Para evitar problemas con la representación del complemento a dos, utilice un 32-bit/64-bitfirmadoentero para representar máscaras
de bits de hasta 30/62 elementos solamente, respectivamente.

36
CAPÍTULO 2. ESTRUCTURAS DE DATOS Y BIBLIOTECAS ©
c Steven y Félix

Ejemplo: 5| 4| 3| 2| 1| 0 <- indexación basada en 0 desde la derecha


32|16| 8| 4| 2| 1 <- potencia de 2
S = 34 (base 10) = 1| 0| 0| 0| 1| 0 (base 2)
F| mi| D| C| B| A <- etiqueta alfabética alternativa

En el ejemplo anterior, el enteroS=34 o100010en binario también representa un pequeño


conjunto{15}con un esquema de indexación basado en 0 en significado de dígito creciente
(o{B, F}usando la etiqueta del alfabeto alternativo) porque el segundo y el sexto bit
(contando desde la derecha) deSestán en.
2. Para multiplicar/dividir un número entero por 2, solo necesitamos desplazar los bits del número entero a la
izquierda/derecha, respectivamente. Esta operación (especialmente la operación de desplazamiento a la izquierda)
es importante para los siguientes ejemplos a continuación. Observe que el truncamiento en la operación de
desplazamiento a la derecha redondea automáticamente la división por 2 hacia abajo, por ejemplo, 17/2 = 8.

S = 34 (base 10) = 100010 (base 2)


S = S << 1 = S * 2 = 68 (base 10) = 1000100 (base 2) S = S >> 2
= S/ 4 = 17 (base 10) = 10001 (base 2)
S = S >> 1 = S / 2 = 8 (base 10) = 1000 (base 2) <- LSB se ha ido
(LSB = bit menos significativo)

3. Para configurar/encender elj-th elemento (indexación basada en 0) del


conjunto, use la operación OR bit a bitS|= (1<<j).

S = 34 (base 10) = 100010 (base 2)


j = 3, 1 << j = 001000 <- el bit '1' se desplaza a la izquierda 3 veces
- - - - - - - - O (verdadero si alguno de los bits es verdadero)
S = 42 (base 10) = 101010 (base 2) // actualice S a este nuevo valor 42

4. Para comprobar si elj-el elemento del conjunto está encendido,

usar la operación AND bit a bitT = S & (1<<j). Sit = 0,


entonces elj-El elemento del conjunto está apagado.
SiT != 0 (para ser preciso,T = (1<<j)),entonces elj-El elemento del conjunto está encendido. Consulte la
Figura 2.1 para ver un ejemplo de este tipo.

S = 42 (base 10) = 101010 (base 2) j = 3,


1 << j = 001000 <- el bit '1' se desplaza a la izquierda 3 veces
- - - - - - - - AND (solo verdadero si ambos bits son verdaderos) =
T = 8 (base 10) 001000 (base 2) -> no es cero, el tercer elemento está activado

S = 42 (base 10) = 101010 (base 2) j = 2,


1 << j = 000100 <- el bit '1' se desplaza a la izquierda 2 veces
--------Y
T = 0 (base 10) = 000000 (base 2) -> cero, el segundo elemento está desactivado

5. Para borrar/apagar elj-el artículo del conjunto,


usar8la operación AND bit a bitS &=∼(1<<j).

S = 42 (base 10) = 101010 (base 2)


j = 1, ~(1 << j) = 111101 <- '~' es la operación NOT bit a bit
--------Y
S = 40 (base 10) = 101000 (base 2) // actualice S a este nuevo valor 40
8Use mucho los corchetes cuando manipule bits para evitar errores accidentales debido a la precedencia del operador.

37
2.2. DS LINEAL CON BIBLIOTECAS INTEGRADAS ©
c Steven y Félix

6. Para alternar (cambiar el estado de) elj-el elemento del


conjunto, use la operación XOR bit a bitS∧= (1<<j).

S = 40 (base 10) = 101000 (base 2)


j = 2, (1 << j) = 000100 <- el bit '1' se desplaza a la izquierda 2 veces
- - - - - - - - XOR <- verdadero si ambos bits son diferentes
S = 44 (base 10) = 101100 (base 2) // actualice S a este nuevo valor 44

S = 40 (base 10) = 101000 (base 2)


j = 3, (1 << j) = 001000 <- el bit '1' se desplaza a la izquierda 3 veces
- - - - - - - - XOR <- verdadero si ambos bits son diferentes
S = 32 (base 10) = 100000 (base 2) // actualice S a este nuevo valor 32

7. Para obtener el valor del bit menos significativo que está activado (primero desde la
derecha), useT = (S & (-S)).

S = 40 (base 10) = = 000...000101000 (32 bits, base 2)


-S -40 (base 10) = 111...111011000 (complemento a dos)
-----------------Y
T = 8 (base 10) = 000...000001000 (el tercer bit desde la derecha está activado)

8. Para encendertodosbits en un conjunto de tamañonorte, usarS = (1<<n) - 1 (cuidado


con los desbordamientos).

Ejemplo para n = 3
S + 1 = 8 (base 10) = 1000 <- el bit '1' se desplaza a la izquierda 3 veces
1
-------
S = 7 (base 10) = 111 (base 2)

Ejemplo para n = 5
S + 1 = 32 (base 10) = 100000 <- el bit '1' se desplaza a la izquierda 5 veces
1
---------
S = 31 (base 10) = 11111 (base 2)

Visualización:www.comp.nus.edu.sg/∼stevenha/visualización/máscara de bits.html
Código fuente:ch2 manipulación de 03 bits.cpp/java

Muchas operaciones de manipulación de bits se escriben como macros de preprocesador en nuestro código
fuente de ejemplo de C/C++ (pero se escriben claramente en nuestro código de ejemplo de Java, ya que Java no
admite macros).

• Lista vinculada: C++ STLlista (JavaLista enlazada)


Aunque esta estructura de datos casi siempre aparece en los libros de texto de estructura de datos y
algoritmos, la lista enlazada generalmente se evita en los problemas típicos (de concurso). Esto se
debe a la ineficiencia en el acceso a los elementos (se debe realizar un escaneo lineal desde el
principio o el final de una lista) y el uso de punteros lo hace propenso a errores de tiempo de
ejecución si no se implementa correctamente. En este libro, casi todas las formas de Lista enlazada
han sido reemplazadas por C++ STL más flexible.vectores (JavaVector).

38
CAPÍTULO 2. ESTRUCTURAS DE DATOS Y BIBLIOTECAS ©
c Steven y Félix

La única excepción es probablemente UVa 11988 - Teclado roto (también conocido como Beiju Text),
donde debe mantener dinámicamente una lista (vinculada) de caracteres e insertar de manera
eficiente un nuevo carácteren cualquier sitioen la lista, es decir, al frente (cabeza), actual o atrás (cola)
de la lista (enlazada). De los problemas UVa de 1903 que los autores han resuelto, es probable que
este sea el único problema de lista enlazada pura que hemos encontrado hasta ahora.

• Pila: C++ STLpila (JavaPila)


Esta estructura de datos se usa a menudo como parte de algoritmos que resuelven ciertos problemas (p.
ej., coincidencia de paréntesis en la Sección 9.4, calculadora de sufijo y conversión de infijo a sufijo en la
Sección 9.27, búsqueda de componentes fuertemente conectados en la Sección 4.2.9 y escaneo de Graham
en la Sección 7.3.7 ). Una pila solo permiteO(1) inserción (empuje) yO(1) eliminación (pop) desde la parte
superior. Este comportamiento suele denominarse último en entrar, primero en salir (LIFO) y recuerda a las
pilas literales del mundo real. STL típico de C++pilalas operaciones incluyenempujar()/pop() (insertar/quitar
de la parte superior de la pila),parte superior() (obtener contenido de la parte superior de la pila), yvacío().

• Cola: C++ STLcola (JavaCola9)


Esta estructura de datos se usa en algoritmos como Breadth First Search (BFS) en la Sección
4.2.2. Una cola solo permiteO(1) inserción (encolar) desde atrás (cola) yO(1) eliminación
(dequeue) desde el frente (cabeza). Este comportamiento también se denomina primero en
entrar, primero en salir (FIFO), al igual que las colas reales en el mundo real. STL típico de C++
colalas operaciones incluyenempujar()/pop() (insertar desde atrás/eliminar desde el frente de la
cola),frente atrás() (obtener contenido de la parte delantera/trasera de la cola), yvacío().

• Cola de dos extremos (Deque): C++ STLdeque (JavaDeque10)


Esta estructura de datos es muy similar a la matriz redimensionable (vector) y la cola anteriores,
excepto que los deques admiten datos rápidos.O(1) inserciones y eliminaciones enambas cosasel
principio y el final del deque. Esta característica es importante en ciertos algoritmos, por ejemplo, el
algoritmo de ventana deslizante en la Sección 9.31. STL típico de C++dequelas operaciones incluyen
empujar hacia atrás(), hacer estallar al frente() (como la cola normal),empujar al frente()y retroceder()
(específico para deque).

Visualización:www.comp.nus.edu.sg/∼stevenha/visualización/lista.html
Código fuente:ch2 04 cola de pila.cpp/java

Ejercicio 2.2.1*: Suponga que le dan unsin clasificarformaciónSdenortenúmeros enteros Resuelva


cada una de las siguientes tareas con los mejores algoritmos posibles que se le ocurran y analice sus
complejidades de tiempo. Supongamos las siguientes restricciones: 1≤norte≤100kde modo queO(
norte2) las soluciones son teóricamente inviables en un entorno de concurso.

1. Determinar siScontiene uno o más pares de enteros duplicados. 2*. dado

un enterov, encuentra dos enterosun, b∈Stal quea+b=v. 3*. Seguimiento de

la pregunta 2: ¿qué pasa si la matriz dadaSesya ordenado?

4*. Imprime los enteros enSque caen entre un rango [una . . . b] (inclusive) en orden

ordenado. 5*. Determine la longitud de la mayor crecientecontiguosubarreglo enS.

6. Determine la mediana (percentil 50) deS. Asumir quenortees impar.

9el JavaColaes solo uninterfazque generalmente se instancia con JavaLista enlazada.


10el JavaDequees también uninterfaz.Dequegeneralmente se instancia con JavaLista enlazada.

39
2.2. DS LINEAL CON BIBLIOTECAS INTEGRADAS ©
c Steven y Félix

Ejercicio 2.2.2: Hay varios otros trucos 'geniales' posibles con técnicas de manipulación de
bits, pero rara vez se usan. Implemente estas tareas con manipulación de bits:

1. Obtenga el resto (módulo) deScuando se divide pornorte(nortees una potencia de 2)


p.ejS= (7)10% (4)10= (111)2% (100)2= (11)2= (3)10.
2. Determinar siSes una potencia de 2
p.ejS= (7)10= (111)2no es una potencia de 2, sino (8)10= (100)2es una potencia de 2

3. Apague el último bit enS, p.ejS= (40)10= (101000)2→S= (32)10= (100000)2.


4. Encienda el último cero enS, p.ejS= (41)10= (101001)2→S= (43)10= (101011)2.
5. Apague la última serie consecutiva de unos enS
p.ejS= (39)10= (100111)2→S= (32)10= (100000)2.
6. Encienda la última serie consecutiva de ceros enS
p.ejS= (36)10= (100100)2→S= (39)10= (100111)2.
7*. Resolver UVa 11173 - Códigos Gray con unun trazador de líneasexpresión de manipulación de bits para cada
caso de prueba, es decir, encontrar elk-th Código Gray.

8*. Invirtamos el problema UVa 11173 anterior. Dado un código gris, encuentre su posiciónk
utilizando la manipulación de bits.

Ejercicio 2.2.3*: También podemos usar unredimensionablematriz (C++ STLvectoro JavaVector)para


implementar una pila eficiente. Averigua cómo lograr esto. Pregunta de seguimiento: ¿Podemos usar un
estáticomatriz, lista enlazada o deque en su lugar? ¿Por qué o por qué no?

Ejercicio 2.2.4*: Podemos usar una lista enlazada (C++ STLlistao JavaLista enlazada)para implementar una
cola eficiente (o deque). Averigua cómo lograr esto. Pregunta de seguimiento: ¿Podemos usar una matriz
redimensionable en su lugar? ¿Por qué o por qué no?

Ejercicios de programación que involucran estructuras de datos lineales (y algoritmos) con bibliotecas:

• Manipulación de matriz 1D, por ejemplo, matriz, C++ STLvectores (o JavaVector/ArrayList)

1.UVa 00230 - Prestatarios(un poco de análisis de cadenas, vea la Sección 6.2; mantener una lista de libros
ordenados; clave de clasificación: los nombres de los autores primero y, si hay empates, por título; el tamaño
de entrada es pequeño aunque no se indica; no necesitamos usar BST balanceado)

2. UVa 00394 - Mapmaker (cualquiernorte-la matriz dimensional se almacena en la memoria de la


computadora como una matriz unidimensional; siga la descripción del problema)

3. UVa 00414: superficies mecanizadas (obtenga el tramo más largo de 'B')


4. UVa 00467 - Señales de sincronización (escaneo lineal, indicador booleano 1D)

5. UVa 00482 - Matrices de permutación (es posible que deba usar un tokenizador de cadena,
consulte la Sección 6.2, ya que no se especifica el tamaño de la matriz)

6. UVa 00591 - Caja de Ladrillos (suma todos los elementos; obtenga el promedio; sume las
diferencias absolutas totales de cada elemento del promedio dividido por dos)

7.UVa 00665 - Moneda Falsa(use banderas booleanas 1D; todas las monedas son inicialmente monedas
falsas potenciales; si '=', todas las monedas a la izquierda y derecha no son monedas falsas; si '<' o '>',
todas las monedas que no están a la izquierda y a la derecha no son monedas falsas; verifique si solo
queda una moneda falsa candidata al final)

8. UVa 00755 - 487-3279 (Tabla de direccionamiento directo; convierta las letras excepto Q y Z a 2-9;
mantenga '0'-'9' como 0-9; ordene los números enteros; encuentre duplicados si los hay)

40
CAPÍTULO 2. ESTRUCTURAS DE DATOS Y BIBLIOTECAS ©
c Steven y Félix

9.UVa 10038 - Jolly Jumpers *(use banderas booleanas 1D para verificar [1..norte -1])
10. UVa 10050 - Hartales (bandera booleana 1D)
11. UVa 10260 - Soundex (Tabla de direccionamiento directo para mapeo de código soundex)

12. UVa 10978 - Let's Play Magic (manipulación de matriz de cadenas 1D)
13UVa 11093 - Solo termínalo(escaneo lineal, matriz circular, un poco desafiante)
14. UVa 11192 - Grupo inverso (matriz de caracteres)
15. UVa 11222: solo lo hice yo (use varias matrices 1D para simplificar este problema)
dieciséis.UVa 11340 - Periódico *(DAT; ver Hashing en la Sección 2.3)
17. UVa 11496 - Musical Loop (almacenar datos en matriz 1D, contar los picos)
18. UVa 11608: sin problemas (use tres matrices: creada; requerida; disponible)
19. UVa 11850 - Alaska (para cada ubicación de número entero de 0 a 1322; ¿puede Brenda llegar a
(cualquier lugar dentro de las 200 millas) de cualquier estación de carga?)

20UVa 12150 - Posición polar(manipulación sencilla)


21UVa 12356 - Amigos del ejército *(similar a la eliminación en listas doblemente enlazadas, pero
aún podemos usar una matriz 1D para la estructura de datos subyacente)

• Manipulación de matriz 2D

1. UVa 00101 - El problema de los bloques (simulación similar a la 'pila'; pero también necesitamos
acceder al contenido de cada pila, por lo que es mejor usar una matriz 2D)

2. UVa 00434 - Matty's Blocks (un tipo de problema de visibilidad en geometría, solucionable con el
uso de manipulación de matriz 2D)

3. UVa 00466 - Mirror Mirror (funciones principales: rotar y reflejar)


4. UVa 00541 - Corrección de errores (cuenta el número de '1's para cada fila/columna; todos
deben ser pares; si∃un error, verifique si está en la misma fila y columna)
5. UVa 10016 - Flip-flop the Squarelotron (tedioso)
6. UVa 10703 - Puntos libres (utilice una matriz booleana 2D de tamaño 500×500)

7.UVa 10855 - Cuadrados rotados *(matriz de cadenas, 90orotación en el sentido de las agujas del reloj)

8.UVa 10920 - Grifo Espiral *(simular el proceso)


9. UVa 11040: agregue ladrillos en la pared (manipulación de matriz 2D no trivial)
10. UVa 11349 - Matriz simétrica (utilice long long para evitar problemas)
11. UVa 11360 - Diviértete con Matrices (haz lo que se te pida)
12UVa 11581 - Sucesores de rejilla *(simular el proceso)
13. UVa 11835 - Fórmula 1 (haz lo que se te pide)

14UVa 12187 - Hermanos(simular el proceso)


15.UVa 12291 - Compositor poliomino(hacer lo que se le pide, un poco tedioso)

dieciséis.UVa 12398 - NumPuzz I(simula al revés, no te olvides de mod 10)


• STL de C++algoritmo (JavaColecciones)
1. UVa 00123 - Búsqueda rápida (función de comparación modificada, usoclasificar)
2.UVa 00146 - Códigos de identificación *(usarsiguiente permutación)

3. UVa 00400 - Unix ls (este comando se usa con mucha frecuencia en UNIX)
4. UVa 00450 - Little Black Book (tedioso problema de clasificación)
5.UVa 00790 - Cefalea del juez principal(similar a UVa 10258)
6. UVa 00855 - Almuerzo en Grid City (clase, mediana)
7. UVa 01209 - Wordfish (LA 3173, Manila06) (STLSiguienteypermutación anterior)
8.UVa 10057 - Una noche de verano...(involucra la mediana, use STLordenar, límite
superior, límite inferiory algunos cheques)

41
2.2. DS LINEAL CON BIBLIOTECAS INTEGRADAS ©
c Steven y Félix

9.UVa 10107 - ¿Qué es la Mediana? *(fiy mediana de uncreciente/lista dinámica de enteros;


aún solucionable con múltiples llamadas deenésimo elementoenalgoritmo)
10. UVa 10194 - Fútbol, también conocido como fútbol (clasificación de campos múltiples, usoclasificar)

11UVa 10258 - Marcador Concurso *(clasificación de campos múltiples, usoclasificar)


12UVa 10698 - Clasificación de fútbol(clasificación de campos múltiples, usoclasificar)

13. UVa 10880 - Colin y Ryan (usoclasificar)


14. UVa 10905 - Juego infantil (función de comparación modificada, usoclasificar)
15. UVa 11039 - Diseño de edificios (usoclasificarluego cuente diferentes signos)
16. UVa 11321 - Ordenar Ordenar y Ordenar (¡cuidado con la modificación negativa!)

17. UVa 11588 - Codificación de imágenes (clasificarsimplifica el problema)


18. UVa 11777 - Automatizar los Grados (clasificarsimplifica el problema)
19. UVa 11824 - A Precio Mínimo De La Tierra (clasificarsimplifica el problema)
20UVa 12541 - Fechas de nacimiento(LA6148, HatYai12,clasificar,elegir el más joven y el más viejo)

• Manipulación de bits (ambos C++ STLconjunto de bits (Javaconjunto de bits)y máscara de bits)

1. UVa 00594 - One Little, Two Little... (manipular cadena de bits conconjunto de bits)
2. UVa 00700 - Errores de fecha (se puede resolver conconjunto de bits)

3. UVa 01241 - Torneo Jollybee (LA 4147, Jakarta08, fácil)


4.UVa 10264 - El rincón más potente*(manipulación pesada de máscara de bits)
5.UVa 11173 - Códigos grises(patrón D & C o manipulación de broca de un revestimiento)
6. UVa 11760 - Hermano Arif, ... (verificaciones separadas de filas y columnas; use dos conjuntos de bits)

7.UVa 11926 - Multitarea *(usar 1Mconjunto de bitspara verificar si una ranura está libre)
8.UVa 11933 - Partición de números *(un ejercicio de manipulación de bits)
9. IOI 2011 - Palomas (este problema se simplifica con la manipulación de bits, pero la
solución final requiere mucho más que eso).

• STL de C++lista (JavaLista enlazada)


1.UVa 11988 - Teclado roto... *(problema raro de lista enlazada)
• STL de C++pila (JavaPila)
1. UVa 00127 - Paciencia "Acordeón" (barajarpila)
2.UVa 00514 - Rieles *(usarpilapara simular el proceso)
3.UVa 00732 - Anagrama por Stack *(usarpilapara simular el proceso)
4.UVa 01062 - Contenedores *(LA 3752, WorldFinals Tokyo07, simulación conpila;
la respuesta máxima es 26 pilas;O(norte) la solución existe)
5. UVa 10858 - Factorización única (usopilapara ayudar a resolver este problema) Ver
también: implícitopilas en llamadas a funciones recursivas y conversión/evaluación
de Postfix en la Sección 9.27.

• STL de C++colaydeque (JavaColayDeque)


1. UVa 00540 - Team Queue ('cola' modificada)
2.UVa 10172 - El cargamento solitario... *(usar amboscolaypila)
3.UVa 10901 - Ferry Cargando III *(simulación concola)
4. UVa 10935 - Tirar cartas I (simulación concola)
5.UVa 11034 - Ferry Cargando IV *(simulación concola)
6.UVa 12100 - Cola de impresión(simulación concola)
7.UVa 12207 - Esta es tu cola(usar amboscolaydeque) Ver
también:colas en BFS (ver Sección 4.2.2)

42
CAPÍTULO 2. ESTRUCTURAS DE DATOS Y BIBLIOTECAS ©
c Steven y Félix

2.3 DS no lineal con bibliotecas integradas


Para algunos problemas, el almacenamiento lineal no es la mejor forma de organizar los datos. Con las
implementaciones eficientes de estructuras de datos no lineales que se muestran a continuación, puede operar
con los datos de manera más rápida, acelerando así los algoritmos que dependen de ellos.
Por ejemplo, si necesita undinámica11colección de pares (por ejemplo, clave→pares de valores), usando C++
STLmapaa continuación puede proporcionarleO(Iniciar sesiónnorte) rendimiento para operaciones de inserción/
búsqueda/eliminación con solo unas pocas líneas de código (que aún tiene que escribir usted mismo), mientras
almacena la misma información dentro de una matriz estática deestructuras puede requerirO(norte) inserción/
búsqueda/eliminación, y tendrá que escribir el código transversal más largo usted mismo.

• Árbol de búsqueda binaria equilibrada (BST): C++ STLmapa/conjunto (JavaMapa de árbol/Conjunto de árbol)
El BST es una forma de organizar los datos en una estructura de árbol. En cada subárbol con raíz enX, se
cumple la siguiente propiedad BST: Elementos en el subárbol izquierdo deXson más pequeños queX y
elementos en el subárbol derecho deXson mayores que (o iguales a)X. Esta es esencialmente una aplicación
de la estrategia Divide y vencerás (ver también la Sección 3.3). Organizar los datos de esta manera (ver
Figura 2.2) permiteO(Iniciar sesiónnorte)buscar(clave), insertar(clave), findMin()/findMax(), sucesor(clave)/
predecesor(clave),yeliminar (clave)ya que en el peor de los casos, sóloO(Iniciar sesiónnorte) se requieren
operaciones en un escaneo de raíz a hoja (ver [7, 5, 54, 12] para más detalles). Sin embargo, esto solo es
válido si el BST está equilibrado.

Figura 2.2: Ejemplos de BST

ImplementarLibre de erroresBST equilibrados como el Adelson-Velskii Landis (AVL)12o Rojo-Negro


(RB)13Trees es una tarea tediosa y difícil de lograr en un entorno de concurso con limitaciones de
tiempo (a menos que haya preparado una biblioteca de código de antemano, consulte la Sección
9.29). Afortunadamente, C++ STL tienemapayestablecer (y java tieneÁrbolMapayconjunto de árboles)
cuales sonnormalmenteimplementaciones del RB Tree que garantiza que las principales operaciones
BST como inserciones/búsquedas/eliminaciones se realicen enO(Iniciar sesiónnorte) tiempo. ¡Al
dominar estas dos clases de plantillas STL de C++ (o API de Java), puede ahorrar mucho tiempo
valioso de codificación durante los concursos! La diferencia entre estas dos estructuras de datos es
simple: el STL de C++mapa (y JavaÁrbolMapa)tiendas (clave→datos) pares mientras que el C++

11El contenido de una estructura de datos dinámica se modifica con frecuencia mediante operaciones de inserción/eliminación/actualización.
12El árbol AVL fue el primer BST autoequilibrado que se inventó. Los árboles AVL son esencialmente BST tradicionales con una
propiedad adicional: las alturas de los dos subárboles de cualquier vértice en un árbol AVL pueden diferir por como mucho uno.
Las operaciones de reequilibrio (rotaciones) se realizan (cuando es necesario) durante las inserciones y eliminaciones para
mantener esta propiedad invariable y, por lo tanto, mantener el árbol más o menos equilibrado.
13El árbol rojo-negro es otro BST autoequilibrado, en el que cada vértice tiene un color: rojo o negro. En los árboles RB, el vértice
de la raíz, todos los vértices de las hojas y los dos hijos de cada vértice rojo son negros. Todo camino simple desde un vértice a
cualquiera de sus hojas descendientes contieneel mismo número de vértices negros. A lo largo de las inserciones y eliminaciones,
un árbol RB mantendrá todas estas invariantes para mantener el árbol equilibrado.

43
2.3. DS NO LINEAL CON BIBLIOTECAS INTEGRADAS ©
c Steven y Félix

STLestablecer (y Javaconjunto de árboles)solo almacena la clave. Para la mayoría de los problemas (de
concurso), usamos unmapa (mapear realmente la información) en lugar de unestablecer (aestablecersolo
es útil para determinar de manera eficiente la existencia de una determinada clave). Sin embargo, hay un
pequeño inconveniente. Si usamos las implementaciones de la biblioteca, se vuelve difícil o imposible
aumentar (agregar información adicional) al BST. Por favor intenteEjercicio 2.3.5*y lea la Sección 9.29 para
obtener más detalles.

Visualización:www.comp.nus.edu.sg/∼stevenha/visualización/bst.html
Código fuente:ch2 05 conjunto de mapas.cpp/java

• Montón: C++ STLcola de prioridad (Javacola de prioridad)


El montón es otra forma de organizar datos en un árbol. El Montón (Binario) también es un árbol
binario como el BST, excepto que debe ser uncompleto14árbol. Los árboles binarios completos se
pueden almacenar de manera eficiente en una matriz compacta indexada 1 de tamañonorte+1, que a
menudo se prefiere a una representación de árbol explícita. Por ejemplo, la matriz A ={N/D, 90, 19,
36, 17, 3, 25, 1, 2, 7}es la representación de matriz compacta de la Figura 2.3 con el índice 0 ignorado.
Uno puede navegar desde un cierto índice (vértice)ia su padre, hijo izquierdo y hijo derecho usando
una manipulación de índice simple: i,2×i, y 2×i+1, respectivamente.
2
Estas manipulaciones de índice se pueden hacer más rápido utilizando técnicas de manipulación de
bits (consulte la Sección 2.2):i>>1, yo<<1,y (i<<1) + 1,respectivamente.

En lugar de aplicar la propiedad BST, el Montón (Max) aplica la propiedad Montón: en cada subárbol
enraizado enX, artículos a la izquierdaysubárboles derechos deXson menores que (o iguales a)X(ver
Figura 2.3). Esta es también una aplicación del concepto Divide y vencerás (ver Sección 3.3). La
propiedad garantiza que la parte superior (o raíz) del montón sea siempre el elemento máximo. No
existe la noción de una 'búsqueda' en el Heap (a diferencia de los BST). En cambio, Heap permite la
extracción rápida (eliminación) del elemento máximo:ExtraerMax()e inserción de nuevos elementos:
Insertar (v)—ambos de los cuales se pueden lograr fácilmente en unO(Iniciar sesiónnorte) transversal
de raíz a hoja o de hoja a raíz, realizando operaciones de intercambio para mantener la propiedad
(Max) Heap siempre que sea necesario (ver [7, 5, 54, 12] para más detalles).

Figura 2.3: Visualización de montones (máx.)

El montón (máximo) es una estructura de datos útil para modelar una cola de prioridad, donde el
elemento con la prioridad más alta (el elemento máximo) se puede quitar de la cola (Extraer Max())

14Un árbol binario completo es un árbol binario en el que todos los niveles, excepto posiblemente el último, están completamente llenos. Todos los
vértices del último nivel también deben rellenarse de izquierda a derecha.

44
CAPÍTULO 2. ESTRUCTURAS DE DATOS Y BIBLIOTECAS ©
c Steven y Félix

y un nuevo artículovse puede poner en cola (Insertar (v)),ambos enO(Iniciar sesiónnorte) tiempo. La
implementación15decola de prioridadestá disponible en C++ STLcolabiblioteca (o Java cola de
prioridad).Las colas de prioridad son un componente importante en algoritmos como los algoritmos
de Prim (y Kruskal) para el problema del árbol de expansión mínimo (MST) (consulte la Sección 4.3), el
algoritmo de Dijkstra para el problema de las rutas más cortas de fuente única (SSSP) (consulte la
Sección 4.4.3) , y el algoritmo de búsqueda A* (consulte la Sección 8.2.5).

Esta estructura de datos también se utiliza para realizarclasificación parcialen C++ STLalgoritmo biblioteca. Una posible
implementación es procesar los elementos uno por uno y crear un Maxdieciséismontón dekelementos, eliminando el
elemento más grande siempre que su tamaño excedak(kes el número de elementos solicitados por el usuario). El mas
pequeñokLuego, los elementos se pueden obtener en orden descendente quitando la cola de los elementos restantes en
Max Heap. Como cada operación de dequeue esO(Iniciar sesiónk),clasificación parcialposeeO(norteIniciar sesiónk)
complejidad del tiempo17. Cuandok=norte, este algoritmo es equivalente a una clasificación de montón. Tenga en cuenta
que aunque la complejidad temporal de una clasificación de montón también esO(norteIniciar sesiónnorte), las
clasificaciones de almacenamiento dinámico suelen ser más lentas que las clasificaciones rápidas porque las operaciones
de almacenamiento dinámico acceden a los datos almacenados en índices distantes y, por lo tanto, no son compatibles
con la memoria caché.

Visualización:www.comp.nus.edu.sg/∼stevenha/visualización/montón.html
Código fuente:ch2 06 cola de prioridad.cpp/java

• Tabla hash: C++11 STLmapa desordenado18(y JavaHashMap/HashSet/HashTable) La tabla hash


es otra estructura de datos no lineal, pero no recomendamos usarla en concursos de
programación a menos que sea absolutamente necesario. Diseñar una función hash de buen
rendimiento suele ser complicado y solo el nuevo C++ 11 es compatible con STL (Java tiene
clases relacionadas con Hash).

Además, C++ STLmapas oestablecers (y JavaÁrbolMapas oÁrbolConjuntos) suelen ser lo suficientemente


rápidos, ya que el tamaño de entrada típico de los problemas (concursos de programación) no suele ser
superior a 1METRO. Dentro de estos límites, laO(1) rendimiento de tablas hash yO(registro 1METRO) el
rendimiento de los BST equilibrados no difiere mucho. Por lo tanto, no discutimos las tablas hash en detalle
en esta sección.

Sin embargo, se puede usar una forma simple de tablas hash en concursos de programación. Las
'tablas de direccionamiento directo' (DAT) pueden considerarse tablas hash en las que las propias
claves son los índices, o en las que la 'función hash' es la función de identidad. Por ejemplo, es
posible que necesitemos asignar todos los caracteres ASCII posibles [0-255] a valores enteros, por
ejemplo, 'a'→'3', 'W'→'10', . . . , 'YO'→'13'. Para este propósito, no necesitamos el C++ STLmapao
cualquier forma de hashing como la clave en sí (el valor del carácter ASCII) es único y suficiente para
determinar el índice apropiado en una matriz de tamaño 256. Algunos ejercicios de programación
que involucran DAT se enumeran en la Sección 2.2 anterior.

15El STL predeterminado de C++cola de prioridades un Max Heap (la eliminación de la cola produce elementos en orden de clave
descendente) mientras que el Java predeterminadoPriorityQueuees un Min Heap (produce elementos en orden de clave
ascendente). Sugerencias: un Max Heap que contiene números se puede convertir fácilmente en un Min Heap (y viceversa)
insertando las claves negadas. Esto se debe a que negar un conjunto de números invertirá su orden de aparición cuando se
clasifiquen. Este truco se usa varias veces en este libro. Sin embargo, si la cola de prioridad se utiliza para almacenarenteros con
signo de 32 bits, se producirá un desbordamiento si−231se niega como 231−1 es el valor máximo de un entero de 32 bits con signo.
dieciséisEl valor por defectoclasificación parcialproduce el más pequeñokelementos en orden ascendente.
17Es posible que haya notado que la complejidad del tiempoO(norteIniciar sesiónk) dóndekes el tamaño de salida ynortees el tamaño de
entrada. Esto significa que el algoritmo es 'sensible a la salida' ya que su tiempo de ejecución depende no solo del tamaño de entrada sino
también de la cantidad de elementos que tiene que generar.
18Tenga en cuenta que C ++ 11 es un nuevo estándar de C ++, es posible que los compiladores más antiguos aún no lo admitan.

45
2.3. DS NO LINEAL CON BIBLIOTECAS INTEGRADAS ©
c Steven y Félix

Ejercicio 2.3.1: Alguien sugirió que es posible almacenar la clave→pares de valores en unmatriz
ordenadadeestructuras para que podamos usar elO(Iniciar sesiónnorte) búsqueda binaria del
problema de ejemplo anterior. ¿Es factible este enfoque? Si no, ¿cuál es el problema?

Ejercicio 2.3.2: No discutiremos los conceptos básicos de las operaciones BST en este libro. En su lugar,
utilizaremos una serie de subtareas para verificar su comprensión de los conceptos relacionados con BST.
Usaremos la figura 2.2 comoreferencia inicialen todas las subtareas excepto la subtarea 2.

1. Mostrar los pasos dados porbuscar(71), buscar(7),y entoncesbuscar (22).


2. Comenzando con unvacíoBST, muestra los pasos dados porinsertar(15), insertar(23),
insertar(6), insertar(71), insertar(50), insertar(4), insertar(7),yinsertar (5).
3. Mostrar los pasos dados porencontrarMin() (yencontrarMax()).

4. Indique elrecorrido en ordende este BST. ¿Está ordenada la salida?


5. Mostrar los pasos dados porsucesor(23), sucesor(7),ysucesor (71).
6. Mostrar los pasos dados porborrar(5) (una hoja),borrar(71) (un nodo interno
con un hijo), y luegoborrar(15) (un nodo interno con dos hijos).

Ejercicio 2.3.3*: Supongamos que se le da una referencia a la raízRde un árbol binario Tque
contienenortevértices. Puede acceder a los vértices primario, izquierdo y derecho de un nodo,
así como a su clave a través de su referencia. Resuelva cada una de las siguientes tareas con los
mejores algoritmos posibles que se le ocurran y analice sus complejidades de tiempo.
Supongamos las siguientes restricciones: 1≤norte≤100kde modo queO(norte2) las soluciones
son teóricamente inviables en un entorno de concurso.

1. Compruebe siTes un BST.

2*. Salida de los elementos enTque están dentro de un rango dado [a..b] en orden ascendente.

3*. Salida del contenido de lahojasdeTenorden descendiente.

Ejercicio 2.3.4*: Se sabe que el recorrido en orden (consulte también la Sección 4.7.2) de un BST estándar
(no necesariamente balanceado) produce el elemento del BST en orden ordenado y se ejecuta enO(norte).
¿El siguiente código también produce los elementos BST en orden? ¿Se puede hacer funcionar en un
tiempo total deO(norte) en vez deO(Iniciar sesiónnorte+ (norte -1)×Iniciar sesiónnorte) = O(norteIniciar
sesiónnorte)? Si es posible, ¿cómo?

x = encontrarMin(); salida
x para (i = 1; i < n; i++) // ¿Este bucle es O(n log n)?
x = sucesor(x); salida x

Ejercicio 2.3.5*: Algunos problemas (difíciles) requieren que escribamosnuestra propia


implementaciones equilibradas del árbol de búsqueda binaria (BST) debido a la necesidad de
aumentar el BST con datos adicionales (consulte el Capítulo 14 de [7]). Desafío: Resuelva UVa 11849 -
CD, que es un problema de BST balanceado puro contu propioimplementación equilibrada de BST
para probar su rendimiento y corrección.

Ejercicio 2.3.6: No discutiremos los conceptos básicos de las operaciones Heap en este libro. En su lugar,
utilizaremos una serie de preguntas para verificar su comprensión de los conceptos de Heap.

46
CAPÍTULO 2. ESTRUCTURAS DE DATOS Y BIBLIOTECAS ©
c Steven y Félix

1. Con la Figura 2.3 como montón inicial, muestre los pasos tomados porInsertar (26).

2. Después de responder la pregunta 1 anterior, muestre los pasos tomados porExtraerMax().

Ejercicio 2.3.7: ¿La estructura está representada por una matriz compacta basada en 1 (ignorando el índice
0) ordenada en orden descendente como Max Heap?

Ejercicio 2.3.8*: Demuestre o refute esta afirmación: “El segundo elemento más grande en un Max
Heap connorte≥3 elementos distintos es siempre uno de los hijos directos de la raíz”. Pregunta de
seguimiento: ¿Qué pasa con el tercer elemento más grande? ¿Dónde está(n) la(s) ubicación(es)
potencial(es) del tercer elemento más grande en un Max Heap?

Ejercicio 2.3.9*: Dada una matriz compacta basada en 1Aque contienenorteenteros (1≤norte≤
100k) que están garantizados para satisfacer la propiedad Max Heap, generan los elementos en
Aque son mayores que un enterov. ¿Cuál es el mejor algoritmo?

Ejercicio 2.3.10*: Dada una matriz desordenadaSdenorteenteros distintos (2k≤norte≤100000),


encuentra el mayor y el menork(1≤k≤32) enteros enSenO(norteIniciar sesiónk). Nota: Para este
ejercicio escrito, suponga que unO(norteIniciar sesiónnorte) el algoritmo esnoaceptable.

Ejercicio 2.3.11*: una operación de montónnosoportado directamente por C++ STL cola de
prioridad (y Javacola de prioridad)es elActualizar clave (índice, nueva clave)operación, que
permite actualizar (aumentar o disminuir) el elemento Heap (Max) en un cierto índice.
Escribetu propioImplementación binaria (Max) Heap con esta operación.

Ejercicio 2.3.12*: Otra operación de montón que puede ser útil es laDeleteKey(índice) operación para
eliminar (Max) elementos Heap en un índice determinado. ¡Implemente esto!

Ejercicio 2.3.13*: Supongamos que solo necesitamos elDecreaseKey (índice, nueva clave) operación,
es decir, unaActualizar claveoperación donde la actualizaciónsiemprehacenueva llavemenor que su
valor anterior. ¿Podemos usar un enfoque más simple que enEjercicio 2.3.11? Sugerencia: Use la
eliminación diferida, usaremos esta técnica en nuestro código Dijkstra en la Sección 4.4.3.

Ejercicio 2.3.14*: ¿Es posible utilizar un BST equilibrado (por ejemplo, C++ STLestablecero Java conjunto de
árboles)para implementar una cola de prioridad con el mismoO(Iniciar sesiónnorte) enqueue y dequeue el
rendimiento? Si es así, ¿cómo? ¿Existen posibles inconvenientes? Si no, ¿por qué?

Ejercicio 2.3.15*: ¿Hay una mejor manera de implementar una cola de prioridad si las claves son todos
números enteros dentro de un rango pequeño, por ejemplo, [0. . .100]? estamos esperando unO(1)
rendimiento en cola y de cola. Si es así, ¿cómo? Si no, ¿por qué?

Ejercicio 2.3.16: ¿Qué estructura de datos no lineal debe usar si tiene que admitir las
siguientes tres operaciones dinámicas: 1) muchas inserciones, 2) muchas
eliminaciones y 3) muchas solicitudes de datos en orden?

Ejercicio 2.3.17: ExistenMETROinstrumentos de cuerda.nortede ellos son únicos (norte≤METRO). ¿Qué


estructura de datos no lineales discutida en esta sección debería usar si tiene que indexar (etiquetar) estos
METROcadenas con enteros de [0..N-1]?El criterio de indexación es el siguiente: la primera cadena debe
recibir un índice de 0; La siguiente cadena diferente debe recibir el índice 1, y así sucesivamente. Sin
embargo, si se vuelve a encontrar una cadena, ¡se le debe dar el mismo índice que su copia anterior! Una
aplicación de esta tarea es construir el gráfico de conexión a partir de una lista de nombres de ciudades
(¡que no son índices enteros!) y una lista de carreteras entre estas ciudades (consulte la Sección 2.4.1). Para
hacer esto, primero tenemos que mapear estos nombres de ciudades en índices enteros (que son mucho
más eficientes para trabajar).

47
2.3. DS NO LINEAL CON BIBLIOTECAS INTEGRADAS ©