Probelma A: Conexión de nodos con aristas de peso variable.
La solución óptima utiliza el algoritmo de Kruskal para el árbol de expansión mínima. El objetivo es conectar todos los nodos con un costo mínimo, considerando aristas con pesos dados y un costo adicional por arista que conecta componentes desconectados.
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX_N = 1e6 + 10;
long long total_cost;
int parent[MAX_N];
struct Edge { int from, to, weight; };
bool compareEdges(Edge a, Edge b) { return a.weight < b.weight; }
int findRoot(int x) {
if (parent[x] == x) return x;
return parent[x] = findRoot(parent[x]);
}
void mergeSets(int x, int y, int w) {
int rootX = findRoot(x), rootY = findRoot(y);
if (rootX == rootY) return;
parent[rootX] = rootY;
total_cost += w;
}
int main() {
int n, m, k, w;
cin >> n >> m >> k >> w;
for (int i = 1; i <= n; i++) parent[i] = i;
Edge edges[MAX_N];
for (int i = 1; i <= m; i++) cin >> edges[i].from >> edges[i].to >> edges[i].weight;
sort(edges + 1, edges + m + 1, compareEdges);
int connected = 0;
for (int i = 1; i <= m; i++) {
if (edges[i].weight > w && connected >= n - 1 - k) break;
mergeSets(edges[i].from, edges[i].to, edges[i].weight);
connected++;
}
for (int i = 1; i <= n; i++) if (findRoot(i) == i) total_cost += w;
total_cost -= w;
cout << total_cost << endl;
return 0;
}
Problema B: Encontrar la submatriz más grande donde todas las submatrices satisfacen una condición específica.
La condición se reduce a verificar que para cualquier matriz 2x2, la suma de las esquinas diagonales cumpla una desigualdad. Esto se puede precomputar para cada celda, convirtiendo el problema en hallar el mayor rectángulo de unos en una matriz binaria, resoluble con una pila monótona.
#include <iostream>
#include <stack>
using namespace std;
const int MAX_DIM = 1e3 + 10;
int grid[MAX_DIM][MAX_DIM], valid[MAX_DIM][MAX_DIM];
int heights[MAX_DIM], width[MAX_DIM];
int main() {
int rows, cols;
cin >> rows >> cols;
for (int i = 1; i <= rows; i++)
for (int j = 1; j <= cols; j++) cin >> grid[i][j];
for (int i = 1; i < rows; i++)
for (int j = 1; j < cols; j++)
valid[i][j] = (grid[i][j] + grid[i+1][j+1] <= grid[i][j+1] + grid[i+1][j]) ? 1 : 0;
int max_area = 0;
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= cols; j++) {
if (valid[i][j] && (i == 1 || valid[i][j] == valid[i-1][j]))
heights[j]++;
else
heights[j] = (valid[i][j]) ? 1 : 0;
}
stack<pair<int, int>> st;
heights[cols + 1] = 0;
for (int j = 1; j <= cols + 1; j++) {
int accumulated = 0;
while (!st.empty() && st.top().first > heights[j]) {
accumulated += st.top().second;
max_area = max(max_area, (accumulated + 1) * (st.top().first + 1));
st.pop();
}
st.push({heights[j], accumulated + 1});
}
}
max_area = max(max_area, max(rows, cols));
cout << max_area << endl;
return 0;
}
Problema C: Dada una permutación del 1 al n, encontrar la siguiente permutación en orden lexicográfico que tenga el mismo número de inversiones.
Una solución aproximada utiliza la función next_permutation para iterar sobre permutaciones, pero esto es ineficiente para n grande. Enfoques más óptimos implican búsqueda binaria para determinar el punto de cambio.
Problema D: Distribuir dulces entre jugadores con reglas que involucran teoría de juegos. Este problema requiere análisis de estrategias óptimas y puede abordarse con programación dinámica o teoremas de equilibrio.