Modern Art
Solución
Pista 1
Intentemos resolver la entrada de ejemplo a mano: ¿se podría aplicar un método similar en el código?
Pista 2
¿Qué propiedad tiene un color que no puede ser el primero en pintarse?
Explicación
Primero, observemos que si dos colores se superponen, sabemos que al menos uno de ellos no puede ser el rectángulo original.
Para cada color , podemos determinar los límites de ese color y considerar su rectángulo envolvente (bounding rectangle). Cualquier otro color que aparezca dentro de este rectángulo en la grilla final debió pintarse después de , y podemos descartar a como el primer color pintado.
Hay que notar que siempre elegimos el rectángulo envolvente más pequeño posible para cada color . Esto es porque un rectángulo más grande crea más intersección entre colores, lo que podría eliminar colores iniciales válidos.
Implementación
Complejidad temporal:
#include <fstream>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
const int MAX_COLOR = 9;
int main() {
/*
* Cajas envolventes de cada uno de los colores.
* El primer elemento no se usa (los colores van de 1 a 9)
*/
vector<int> left(MAX_COLOR + 1);
vector<int> right(MAX_COLOR + 1);
vector<int> up(MAX_COLOR + 1);
vector<int> down(MAX_COLOR + 1);
for (int c = 1; c <= MAX_COLOR; c++) {
left[c] = up[c] = INT32_MAX;
right[c] = down[c] = -1;
}
vector<bool> valid_start(MAX_COLOR + 1);
std::ifstream read("art.in");
int width;
read >> width;
vector<vector<int>> art(width, vector<int>(width));
for (int r = 0; r < width; r++) {
for (int c = 0; c < width; c++) {
char curr_char;
read >> curr_char;
int curr = curr_char - '0';
art[r][c] = curr;
if (curr != 0) {
left[curr] = std::min(left[curr], c);
right[curr] = std::max(right[curr], c);
down[curr] = std::max(down[curr], r);
up[curr] = std::min(up[curr], r);
valid_start[curr] = true;
}
}
}
for (int color = 1; color <= MAX_COLOR; color++) {
for (int r = up[color]; r <= down[color]; r++) {
for (int c = left[color]; c <= right[color]; c++) {
if (art[r][c] != color) { valid_start[art[r][c]] = false; }
}
}
}
int total_starts = 0;
for (bool s : valid_start) { total_starts += s ? 1 : 0; }
std::ofstream("art.out") << total_starts << endl;
}import java.io.*;
public class Art {
static final int MAX_COLOR = 9;
public static void main(String[] args) throws IOException {
BufferedReader read = new BufferedReader(new FileReader("art.in"));
int width = Integer.parseInt(read.readLine());
/*
* Cajas envolventes de cada uno de los colores.
* El primer elemento no se usa (los colores van de 1 a 9)
*/
int[] left = new int[MAX_COLOR + 1];
int[] right = new int[MAX_COLOR + 1];
int[] down = new int[MAX_COLOR + 1];
int[] up = new int[MAX_COLOR + 1];
for (int c = 1; c <= MAX_COLOR; c++) {
left[c] = up[c] = Integer.MAX_VALUE;
right[c] = down[c] = -1;
}
boolean[] validStart = new boolean[MAX_COLOR + 1];
int[][] art = new int[width][width];
for (int r = 0; r < width; r++) {
String row = read.readLine();
for (int c = 0; c < width; c++) {
int curr = Character.getNumericValue(row.charAt(c));
art[r][c] = curr;
if (curr != 0) {
left[curr] = Math.min(left[curr], c);
right[curr] = Math.max(right[curr], c);
down[curr] = Math.max(down[curr], r);
up[curr] = Math.min(up[curr], r);
validStart[curr] = true;
}
}
}
for (int color = 1; color <= MAX_COLOR; color++) {
for (int r = up[color]; r <= down[color]; r++) {
for (int c = left[color]; c <= right[color]; c++) {
if (art[r][c] != color) { validStart[art[r][c]] = false; }
}
}
}
int totalStarts = 0;
for (boolean c : validStart) { totalStarts += c ? 1 : 0; }
PrintWriter written = new PrintWriter("art.out");
written.print(totalStarts);
written.close();
}
}MAX_COLOR = 9
"""
Cajas envolventes de cada uno de los colores.
El primer elemento no se usa (los colores van de 1 a 9)
"""
left = [0] * (MAX_COLOR + 1)
right = [0] * (MAX_COLOR + 1)
down = [0] * (MAX_COLOR + 1)
up = [0] * (MAX_COLOR + 1)
for c in range(1, MAX_COLOR + 1):
left[c], up[c] = float("inf"), float("inf")
right[c], down[c] = -1, -1
valid_start = [False] * (MAX_COLOR + 1)
with open("art.in") as read:
n = int(read.readline().strip())
art = [None] * n
for r in range(n):
art[r] = [int(x) for x in read.readline().strip()]
for c in range(n):
if art[r][c] != 0:
curr = art[r][c]
left[curr] = min(left[curr], c)
right[curr] = max(right[curr], c)
down[curr] = max(down[curr], r)
up[curr] = min(up[curr], r)
valid_start[curr] = True
for color in range(1, MAX_COLOR + 1):
if left[color] == float("inf"):
continue
for c in range(int(up[color]), int(down[color] + 1)):
for k in range(int(left[color]), int(right[color] + 1)):
if art[c][k] != color:
other = art[c][k]
if other != 0 and other != color:
valid_start[other] = False
print(sum(valid_start), file=open("art.out", "w"))