![]() |
Problema B - Constelação Retangular |
Tipo de problema: Geometria
Autor do Problema: Pedro Ribeiro (DCC/FCUP)
Problema:
Dadas as coordenadas inteiras de N estrelas, a tua tarefa é
descobrir qual é o maior número de estrelas que se conseguem
colocar no contorno de um único retângulo com dois lados
verticais e dois lados horizontais.
Restrições:
São garantidos os seguintes limites em todos os casos de teste
que irão ser colocados ao programa:
1 ≤ N ≤ 90 000 | Número de estrelas | |
1 ≤ Yi, Xi ≤ 300 | Coordenadas das estrelas |
Solução Base:
A solução mais simples de todas passa por primeiro construir uma
lista ordenada de linhas e uma lista ordenada de colunas. Por
lista ordenada significa que uma linha com coordenada y menor
que outra vem primeiro na lista. Para cada linha/coluna temos
uma lista de pontos (só precisamos de uma coordenada) que estão
presentes nessa lista/coluna. Agora para obter a resposta basta
considerar cada conjunto de 2 linhas mais 2 colunas, que
equivale a 4 ciclos encadeados, e para cada par de 2 linhas mais
2 colunas contamos o número de pontos nesse retângulo (notem que
o retângulo não equivale à soma dos pontos em cada linha/coluna,
pois há pontos que ficam de fora, ver estrelas a vermelho na
imagem a seguir).
Se considerarmos o número de linhas/colunas como K, temos que a solução vai depender deste valor. Notem que este valor depende do valor das coordenadas máximas (pois não pode haver mais linhas que o valor das coordenadas máximas).
Esta seria uma solução O(K ^ 5) que daria aproximadamente 30 pontos.
Solução Melhor:
Uma ideia interessante para remover a contagem de pontos seria
recorrer a somas acumuladas. Neste caso vamos considerar somas
acumuladas entre linhas/colunas. Consideremos duas
matrizes, lsums[i1][i2]
e csums[j1][j2], que representam,
respetivamente, o número de pontos na linha i1
desde a coluna 0 à i2 e o número de pontos na
coluna j1 desde a linha 0
à j2 (estamos a considerar que a lista começa
em 0). Sem perda de generalidade vamos calcular a matriz de
somas apenas para as linhas (as colunas são análogas).
Para calcular cada valor de lsums[i1][i2] é necessário primeiro considerar cada linha i1. Depois, para cada linha i1, temos que o valor de list[i1][i2] = list[i1][i2 - 1] + <número de pontos na coluna i2 e na linha i1> (este último valor pode ser guardado numa matriz à parte aquando do processamento do input, mas pode inclusivé ser guardado na própria matriz list[][]).
Tendo estas matrizes calcular a soma de pontos em qualquer retângulo torna-se fácil, considerando que temos as linhas l1 e l2 e as colunas c1 e c1, a soma de estrelas é igual a: (lsums[l1][c2] - lsums[l1][c1 - 1]) + (lsums[l2][c2] - lsums[l2][c1 - 1]) + (csums[c1][l2] - csums[c1][l1 - 1]) + (csums[c2][l2] - csums[c2][l1]) (cuidado com os casos extremos, quando por exemplo c/l = 0).
Esta seria uma solução O(K ^ 4) que daria aproximadamente 60 pontos.
Solução Ótima:
A solução ótima não é muito diferente da anterior. Considerando
que temos as mesmas matrizes de somas acumuladas, o truque é
perceber como fixando duas linhas, ir apenas buscar as melhores
duas colunas nesse intervalo. Sendo assim a solução passa por
primeiro contruir uma matriz M[o], que representa o
max(<número de estrelas na coluna i entre as duas
linhas fixadas> + <número de estrelas à esquerda da
coluna i para cada uma das linhas fixadas>) [todos
estes valores são calculados usando as matrizes de somas
acumuladas], com i a variar entre o e o número
máximo de colunas (o que significa que esta matriz é construida
da direita para a esquerda).
Tendo a matriz M[o] calculada, agora basta fazer um ciclo desde a coluna 0 até à última coluna e para cada coluna i temos que o retângulo máximo é aquele que tem o valor máximo para colunas à direita de i, que corresponde ao valor de M[i + 1] ("+1" pois não inclui a própria coluna). Sendo assim, o valor para essa coluna é: M[i + 1] + <número de estrelas na coluna i entre as duas linhas fixadas> - <número de estrelas à esquerda da coluna i para cada uma das linhas fixadas> (retiramos o último valor pois só queremos as estrelas entre a coluna i e a coluna ótima e no cálculo de M[] para essa coluna adicionamos a mais, para aproveitar a matriz de somas acumuladas). Notem que esta solução assume que as linhas e colunas estão ordenadas como previsto na solução base. É também necessário cuidado com casos onde só há uma coluna ou só uma linha.
Como para cada duas linhas só temos um ciclo encadeado, então a solução melhora por um fator de K.
Esta seria uma solução O(K ^ 3) que daria aproximadamente 100 pontos.
Ligações interessantes: