{"id":26289084,"url":"https://github.com/dfleta/greedy-search","last_synced_at":"2026-04-28T19:34:39.058Z","repository":{"id":325959985,"uuid":"943386035","full_name":"dfleta/greedy-search","owner":"dfleta","description":"Set covering problem: USA radio stations","archived":false,"fork":false,"pushed_at":"2025-11-26T14:20:16.000Z","size":237,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-28T02:30:59.823Z","etag":null,"topics":["greedy-search","ia-algorithms","optimization-algorithms","optimization-problem","python-sets","set-covering-problem"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dfleta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-05T16:14:40.000Z","updated_at":"2025-11-26T14:20:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dfleta/greedy-search","commit_stats":null,"previous_names":["dfleta/greedy-search"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dfleta/greedy-search","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fgreedy-search","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fgreedy-search/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fgreedy-search/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fgreedy-search/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dfleta","download_url":"https://codeload.github.com/dfleta/greedy-search/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fgreedy-search/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32396332,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T14:34:11.604Z","status":"ssl_error","status_checked_at":"2026-04-28T14:32:37.009Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["greedy-search","ia-algorithms","optimization-algorithms","optimization-problem","python-sets","set-covering-problem"],"created_at":"2025-03-14T22:16:59.244Z","updated_at":"2026-04-28T19:34:39.052Z","avatar_url":"https://github.com/dfleta.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Optimización de Cobertura de Estaciones de Radio\n\n## Descripción del Problema\nEste proyecto aborda un problema clásico de optimización en Inteligencia Artificial conocido como \"_Set Covering Problem_\".\n\nEl objetivo es encontrar el número mínimo de estaciones de radio necesarias para cubrir todos los estados de Estados Unidos (específicamente, los estados del oeste y centro del país).\n\nEstá basado en el ejercicio propuesto en el capítulo 8 _Greedy Algorithms_ del libro grokking [_Algorithms: An illustrated guide for programmers and other curious people_ de Aditya Y. Bhargava](https://github.com/egonSchiele/grokking_algorithms)\n\n## Instalación y Configuración\n\n### Requisitos Previos\n- Python ≥ 3.11\n- [uv](https://github.com/astral-sh/uv) (gestor de paquetes de Python)\n\n### Tkinter\n\n`plt.show()` con Python 3.12 necesita un backend interactivo (TkAgg, Qt5Agg, Gtk3Agg) y una librería GUI instalada.\n\nEn Linux, por ejemplo:\n\n`sudo apt-get install -y python3-tk` para TkAgg\n\no \n\n`pip install PyQt5` para Qt5Agg\n\n\n### Instalación\n\n1. Clonar el repositorio:\n```bash\ngit clone https://github.com/dfleta/greedy-search.git\ncd greedy-search\n```\n\n2. Crear y activar un entorno virtual con uv:\n\n```bash\npython -m pip install uv\n\nuv venv\n\nsource .venv/bin/activate  # En Linux/MacOS\n# o\n.venv\\Scripts\\activate     # En Windows\n```\n\n3. Instalar las dependencias:\n```bash\nuv sync\n```\n\n4. (Opcional) Instalar dependencias de desarrollo:\n```bash\nuv sync --all-groups\n```\n\no \n\n```bash\nuv add --group dev\n```\n\n### Dependencias Principales\n- matplotlib ≥ 3.10.1\n\n#### Dependencias de desarrollo\n- pytest \u003e= 9.0.1\n- ruff ≥ 0.9.9 (para linting, opcional)\n\n### Uso\n\n`uv run main.py`\n\no\n\n`python3 main.py`\n\n### Testing\n\n`uv run pytest`\n\nCon _markers_ listados en [pyproject.toml](./pyproject.toml)\n\n`uv run pytest -m \"greedy_search_global\"`\n\n`uv run pytest -m \"find_best_station\"`\n\n\n### Contexto\n- Necesitamos cobertura de radio en un conjunto de estados, todos los situados al oeste del río Mississippi para promocionar el disco _country_ de Beyoncé _Cowboy Carter_.\n- Existen varias estaciones de radio, cada una cubriendo diferentes conjuntos de estados.\n- Queremos seleccionar el menor número de estaciones posible que cubran todos los estados requeridos, porque Beyoncé -en modo gano o muero- paga la promoción del disco de su bolsillo. Las estaciones al oeste del Misisipi tienen un código que empieza por la letra `K`.\n\n### Cobertura de Estaciones\n\nLa siguiente tabla muestra los estados que cubre cada estación de radio:\n\n| Estación   | Estados Cubiertos |\n|------------|------------------|\n| kone       | Idaho (ID), Nevada (NV), Utah (UT) |\n| ktwo       | Washington (WA), Idaho (ID), Montana (MT) |\n| kthree     | Oregon (OR), Nevada (NV), California (CA) |\n| kfour      | Nevada (NV), Utah (UT) |\n| kfive      | California (CA), Arizona (AZ) |\n| ksix       | New Mexico (NM), Texas (TX), Oklahoma (OK) |\n| kseven     | Oklahoma (OK), Kansas (KS), Colorado (CO) |\n| keight     | Kansas (KS), Colorado (CO), Nebraska (NE) |\n| knine      | Nebraska (NE), South Dakota (SD), Wyoming (WY) |\n| kten       | North Dakota (ND), Iowa (IA) |\n| keleven    | Minnesota (MN), Missouri (MO), Arkansas (AR) |\n| ktwelve    | Louisiana (LA) |\n| kthirteen  | Missouri (MO), Arkansas (AR) |\n\n![K/W Call Letters in the United States](https://earlyradiohistory.us/kwbigmap.gif)\n*K/W Call Letters in the United States*\n\n![Lista de estados USA y abreviaciones](https://upload.wikimedia.org/wikipedia/commons/6/6c/US_state_abbrev_map.png) \n\n*List of U.S. state and territory abbreviations*\n\n## Implementación\n\nEl proyecto implementa dos estrategias diferentes de búsqueda:\n\n### 1. Búsqueda Ávida Global (`greedy_search_global`)\n\nEsta función implementa una estrategia de búsqueda voraz (_greedy_) que:\n- En cada paso, selecciona la estación que cubre el mayor número de estados no cubiertos hasta el momento.\n- Mantiene un registro de los estados cubiertos y las estaciones seleccionadas.\n- Escapa de mínimos locales al considerar siempre la mejor opción global disponible.\n\n![Evolución de la búsqueda ávida global](doc/greedy_search_global.png)\n*La gráfica muestra cómo cada estación seleccionada contribuye a la cobertura total de estados*\n\n### 2. Búsqueda Ávida Local (`greedy_search_local`)\n\nEsta función demuestra el problema de los mínimos locales:\n- Realiza múltiples intentos aleatorios seleccionando 10 estaciones en cada iteración.\n- No considera la optimización global, sino que se basa en selecciones aleatorias.\n- Queda atrapada en mínimos locales, resultando en soluciones subóptimas.\n\n![Mínimos locales y global en la búsqueda](doc/f_minimo_global.png)\n*La gráfica muestra cómo diferentes iteraciones quedan atrapadas en mínimos locales, aún alcanzando en una de ellas el mínimo global.*\n\n![Mínimos locales en la búsqueda](doc/f_minimos_locales.png)\n*La gráfica muestra cómo diferentes iteraciones quedan atrapadas en mínimos locales, sin alcanzar la cobertura total.*\n\n## Resultados\n- La búsqueda ávida global encuentra una solución óptima o cercana a la óptima.\n- La búsqueda local demuestra cómo las estrategias no optimizadas pueden quedar atrapadas en soluciones subóptimas.\n- Las gráficas permiten comparar la efectividad de ambos enfoques.\n\n#### Lógica del Algoritmo \n\n`greedy_search_global`\n\n**Consulta el [_notebook_ conjuntos / sets](https://github.com/dfleta/python-fundamentals-nb/blob/main/notebooks/conjuntos.ipynb) para estudiar las operaciones sobre esta colección Python** de las que vamos a hacer uso.\n\n1. **Inicialización**:\n   - Mantiene un conjunto `covered_states` para registrar los estados ya cubiertos.\n   - Una lista `stations_needed` para almacenar las estaciones seleccionadas.\n   - Listas `gradients` y `num_states_covered` para monitorizar el progreso.\n\n2. **Bucle Principal**:\n   Mientras existan estados sin cubrir (`covered_states \u003c needed_states`):\n   \n   a. **Selección de la Mejor Estación**:\n      - Para cada estación restante, calcula cuántos nuevos estados cubriría: `new_states = station_states - covered_states`.\n      - Selecciona la estación que cubra el mayor número de estados nuevos\n   \n   b. **Actualización del Estado**:\n      - Registra el gradiente (número de nuevos estados cubiertos).\n      - Actualiza el conjunto de estados cubiertos.\n      - Añade la estación a la lista de seleccionadas.\n      - Elimina la estación seleccionada del conjunto disponible.\n\n3. **Visualización**:\n   - Genera un gráfico de barras mostrando:\n     - Eje X: Estaciones seleccionadas en orden.\n     - Eje Y: Número total de estados cubiertos en cada paso.\n\n#### Características Clave\n- **Optimización Global**: En cada paso, selecciona la mejor opción disponible.\n- **Sin Retroceso**: Las decisiones tomadas son definitivas.\n- **Monitorización**: Registra el progreso y la efectividad de cada selección.\n- **Terminación**: El algoritmo se detiene cuando se cubren todos los estados necesarios.\n\n\n## Referencias\n- [Call Letters in the United States](https://earlyradiohistory.us/kwtrivia.htm)\n- [Call signs in the United States](https://en.wikipedia.org/wiki/Call_signs_in_the_United_States)\n- [List of FM radio stations in the United States by call sign (initial letters KK–KM)](https://en.wikipedia.org/wiki/List_of_FM_radio_stations_in_the_United_States_by_call_sign_(initial_letters_KK%E2%80%93KM))\n- [List of U.S. state and territory abbreviations](https://en.wikipedia.org/wiki/List_of_U.S._state_and_territory_abbreviations)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfleta%2Fgreedy-search","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdfleta%2Fgreedy-search","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfleta%2Fgreedy-search/lists"}