Ao pensar em um problema, percebi que precisava criar um algoritmo eficiente para resolver a seguinte tarefa:
O problema: recebemos uma caixa quadrada bidimensional do lado cujos lados são paralelos aos eixos. Podemos examiná-lo através do topo. No entanto, também existem segmentos horizontais. Cada segmento tem um inteiro coordenada x ( ) e -coordena ( ) e pontos Connects e (veja o imagem abaixo).
Gostaríamos de saber, para cada segmento de unidade na parte superior da caixa, quão profundo podemos olhar verticalmente dentro da caixa se examinarmos esse segmento.
Exemplo: dados e segmentos localizados como na figura abaixo, o resultado é . Veja como a luz profunda pode entrar na caixa.
Felizmente para nós, tanto e são bastante pequeno e podemos fazer os cálculos off-line.
O algoritmo mais fácil de resolver esse problema é a força bruta: para cada segmento, percorra toda a matriz e atualize-a sempre que necessário. No entanto, isso nos dá um não muito impressionante .
Uma grande melhoria é usar uma árvore de segmentos capaz de maximizar valores no segmento durante a consulta e ler os valores finais. Não vou descrevê-lo mais, mas vemos que a complexidade do tempo é .
No entanto, criei um algoritmo mais rápido:
Esboço:
Classifique os segmentos em ordem decrescente de coordenada (tempo linear usando uma variação da classificação de contagem). Agora observe que, se qualquer segmento de unidade já foi coberto por qualquer segmento antes, nenhum segmento a seguir poderá limitar o feixe de luz que passa por esse segmento de unidade . Em seguida, faremos uma varredura de linha de cima para baixo na caixa.x x
Agora, vamos introduzir algumas definições: o segmento da unidade é um segmento horizontal imaginário na varredura cujos coordenadas são números inteiros e cujo comprimento é 1. Cada segmento durante o processo de varredura pode ser desmarcado (ou seja, um feixe de luz saindo do o topo da caixa pode alcançar esse segmento) ou marcado (caso oposto). Considere um segmento de unidade com , sempre desmarcado. Vamos também introduzir os conjuntos . Cada conjunto conterá uma sequência inteira de segmentos de unidades marcados consecutivos (se houver algum) com a seguinte marca não marcadax x x 1 = n x 2 = n + 1 S 0 = { 0 } , S 1 = { 1 } , … , S n = { n } x segmento.
Precisamos de uma estrutura de dados capaz de operar nesses segmentos e conjuntos com eficiência. Usaremos uma estrutura de união de busca estendida por um campo que contém o índice máximo do segmento de unidades (índice do segmento não marcado ).
Agora podemos lidar com os segmentos com eficiência. Digamos que agora estamos considerando o ésimo segmento em ordem (chame de "consulta"), que começa em e termina em . Precisamos encontrar todos os segmentos não marcados da unidade que estão contidos no ésimo segmento (esses são exatamente os segmentos nos quais o feixe de luz terminará). Vamos fazer o seguinte: primeiro, encontramos o primeiro segmento não marcado dentro da consulta ( encontre o representante do conjunto no qual está contido e obtenha o índice máximo desse conjunto, que é o segmento não marcado por definição ). Então este índicex 1 x 2 x i x 1 x y x x + 1 x ≥ está dentro da consulta, adicioná-lo para o resultado (o resultado para este segmento é ) e marcar este índice ( União conjuntos contendo e ). Em seguida, repita esse procedimento até encontrarmos todos os segmentos não marcados , ou seja, a próxima consulta Find nos fornece o índice .
Observe que cada operação de união de localização será realizada em apenas dois casos: ou começamos a considerar um segmento (que pode acontecer vezes) ou apenas marcamos um segmento de unidade (isso pode acontecer vezes). Assim, a complexidade geral é ( é uma função inversa de Ackermann ). Se algo não estiver claro, posso elaborar mais sobre isso. Talvez eu possa adicionar algumas fotos se tiver algum tempo.x n O ( ( n + m ) α ( n ) ) α
Agora cheguei ao "muro". Não consigo criar um algoritmo linear, embora pareça que deveria haver um. Então, eu tenho duas perguntas:
- Existe um algoritmo de tempo linear (ou seja, ) resolvendo o problema de visibilidade do segmento horizontal?
- Caso contrário, qual é a prova de que o problema de visibilidade é ?
Respostas:
find ( ) pode ser implementado usando uma matriz de bits com bits. Agora, sempre que removermos ou adicionarmos um elemento a , podemos atualizar esse número inteiro, definindo um pouco como true ou false, respectivamente. Agora você tem duas opções, dependendo da linguagem de programação usada e a suposição é relativamente pequena, ou seja, menor que o que é pelo menos 64 bits ou uma quantidade fixa desses números inteiros:n L n l o n g l o n g i n tmax n L n longlongint
Eu sei que isso é um hack porque assume um valor máximo para e, portanto, pode ser visto como uma constante então ...nn n
fonte
long long int
como pelo menos o tipo inteiro de 64 bits. No entanto, não será que se for enorme e denotarmos o tamanho da palavra como (geralmente ), cada um levará tempo ? Em seguida, terminaríamos com total . w w = 64 O ( nfind
O(mnEu não tenho um algoritmo linear, mas este parece ser O (m log m).
Classifique os segmentos com base na primeira coordenada e altura. Isso significa que (x1, l1) sempre vem antes (x2, l2) sempre que x1 <x2. Além disso, (x1, l1) na altura y1 vem antes (x1, l2) na altura y2 sempre que y1> y2.
Para cada subconjunto com a mesma primeira coordenada, fazemos o seguinte. Seja o primeiro segmento (x1, L). Para todos os outros segmentos do subconjunto: se o segmento for maior que o primeiro, altere-o de (x1, xt) para (L, xt) e adicione-o ao subconjunto L na ordem correta. Caso contrário, solte-o. Finalmente, se o próximo subconjunto tiver uma primeira coordenada menor que L, divida (x1, L) em (x1, x2) e (x2, L). Adicione (x2, L) ao próximo subconjunto na ordem correta. Podemos fazer isso porque o primeiro segmento do subconjunto é mais alto e cobre o intervalo de (x1, L). Esse novo segmento pode ser o que cobre (L, x2), mas não saberemos isso até que olhemos para o subconjunto que tem a primeira coordenada L.
Depois de percorrermos todos os subconjuntos, teremos um conjunto de segmentos que não se sobrepõem. Para determinar qual é o valor Y para um determinado X, precisamos apenas percorrer os segmentos restantes.
Então, qual é a complexidade aqui: A classificação é O (m log m). O loop entre os subconjuntos é O (m). Uma pesquisa também é O (m).
Portanto, parece que esse algoritmo é independente de n.
fonte