Notas Técnicas de Programación en una Competencia Simulada

En competencias de programación, se presentan problemas que requieren estrategias algorítmicas específicas. A continuación, se describen soluciones para varios problemas comunes.

Problema A: Sumas de Dígitos Inversas

Este problema se resuelve precalculando el triángulo de Pascal y aplicando búsqueda en profundidad (DFS) para explorar secuencias. Una implementación puede usar arreglos multidimensionales para coeficientes.


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 15;
int mark[MAXN], perm[MAXN];
int pascal[MAXN][MAXN][MAXN];
int n, goal, found;

void dfs(int idx, int current) {
    if (found) return;
    if (idx > n) {
        if (current == goal) {
            found = 1;
            for (int i = 1; i <= n; i++) cout << perm[i] << " ";
        }
        return;
    }
    if (current > goal || (current == goal && idx <= n)) return;
    for (int i = 1; i <= n; i++) {
        if (found) return;
        if (!mark[i]) {
            mark[i] = 1;
            perm[idx] = i;
            dfs(idx + 1, current + i * pascal[n][1][idx]);
            mark[i] = 0;
        }
    }
}

int main() {
    cin >> n >> goal;
    for (int i = 1; i <= n; i++) pascal[1][i][i] = 1;
    for (int layer = 2; layer <= n; layer++)
        for (int start = 1; start <= n - layer + 1; start++)
            for (int col = 1; col <= n; col++)
                pascal[layer][start][col] = pascal[layer-1][start][col] + pascal[layer-1][start+1][col];
    found = 0;
    dfs(1, 0);
    return 0;
}

Problema P4026: Deudas Cíclicas

Este problema se puede abordar con programación dinámica o DFS con poda. La solución involucra calcular el mínimo de transaciones para equilibrar deudas entre tres entidades.


#include<bits/stdc++.h>
using namespace std;
const int LIM = 1e9;
int debt[3], bills[3][6], totalBills[6];
int values[6] = {100, 50, 20, 10, 5, 1};
int minOps = LIM;

int evaluate() {
    int sum = 0;
    int temp[3];
    for (int i = 0; i < 3; i++) {
        temp[i] = debt[i];
        for (int j = 0; j < 5; j++) temp[i] += values[j] * (bills[i][j] - bills[i][j+1]);
        if (temp[i] < 0 && abs(temp[i]) > bills[i][5]) return LIM;
        sum += abs(temp[i]);
    }
    return sum / 2;
}

int calcSwap(int idx) {
    return (abs(bills[0][idx] - bills[1][idx]) + abs(bills[1][idx] - bills[2][idx]) + abs(bills[2][idx] - bills[0][idx])) / 2;
}

void dfs(int depth, int cur) {
    if (cur >= minOps) return;
    if (depth == 5) {
        minOps = min(minOps, cur + evaluate());
        return;
    }
    for (int i = 0; i <= totalBills[depth]; i++)
        for (int j = 0; j <= totalBills[depth] - i; j++) {
            bills[0][depth] = i;
            bills[1][depth] = j;
            bills[2][depth] = totalBills[depth] - i - j;
            dfs(depth + 1, cur + calcSwap(depth));
        }
}

int main() {
    int p, q, r;
    cin >> p >> q >> r;
    debt[0] = -p + r;
    debt[1] = -q + p;
    debt[2] = -r + q;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 6; j++) {
            cin >> bills[i][j];
            totalBills[j] += bills[i][j];
        }
    minOps = LIM;
    dfs(0, 0);
    if (minOps == LIM) cout << "impossible";
    else cout << minOps;
    return 0;
}

Problema Maze 2D

La solución óptima utiliza árboles de segmentos para mantener distancias entre esquinas opuestas, o salto binario (倍增) para consultas estáticas. Un árbol de segmentos almacana cuatro valores por intervalo: las distancias mínimas entre esquinas opuestas del laberinto.

Problema Pirate Chest

Para este problema, se implementó un enfoque de fuerza bruta, aunque con limitaciones en la eficiencia durante la competencia.

Etiquetas: Segment Tree binary lifting dynamic programming DFS Competitive Programming

Publicado el 7-6 18:53