Este é um desafio na internet solicitado pela Palantir Technologies em suas entrevistas .
Um grupo de agricultores tem alguns dados de elevação e vamos ajudá-los a entender como a chuva flui sobre suas terras agrícolas. Representaremos a terra como uma matriz bidimensional de altitudes e usaremos o modelo a seguir, com base na ideia de que a água flui ladeira abaixo:
Se as quatro células vizinhas de uma célula têm altitudes mais altas, chamamos essa célula de pia; a água se acumula nas pias. Caso contrário, a água fluirá para a célula vizinha com a menor altitude. Se uma célula não é um coletor, você pode assumir que ele tem um vizinho mais baixo exclusivo e que esse vizinho será menor que a célula.
Diz-se que as células que drenam para a mesma pia - direta ou indiretamente - fazem parte da mesma bacia.
Seu desafio é particionar o mapa em bacias. Em particular, dado um mapa de elevações, seu código deve particionar o mapa em bacias e gerar os tamanhos das bacias, em ordem decrescente.
Suponha que os mapas de elevação sejam quadrados. A entrada começará com uma linha com um número inteiro, S, a altura (e largura) do mapa. As próximas linhas S conterão uma linha do mapa, cada uma com S inteiros - as elevações das células S na linha. Alguns fazendeiros têm pequenos terrenos, como os exemplos abaixo, enquanto outros têm terrenos maiores. No entanto, em nenhum caso o agricultor terá um terreno maior que S = 5000.
Seu código deve gerar uma lista separada por espaços dos tamanhos da bacia, em ordem decrescente. (Os espaços à direita são ignorados.)
Alguns exemplos estão abaixo.
Entrada:
3
1 5 2
2 4 7
3 6 9
Resultado:
7 2
As bacias, rotuladas com A e B, são:
A A B
A A B
A A A
Entrada:
1
10
Resultado:
1
Existe apenas uma bacia neste caso.
Entrada:
5
1 0 2 5 8
2 3 4 7 9
3 5 7 8 9
1 2 5 4 2
3 3 5 2 1
Resultado:
11 7 7
As bacias, rotuladas com A, B e C, são:
A A A A A
A A A A A
B B A C C
B B B C C
B B C C C
Entrada:
4
0 2 1 3
2 1 0 4
3 3 3 3
5 5 2 1
Resultado:
7 5 4
As bacias, rotuladas com A, B e C, são:
A A B B
A B B B
A B B C
A C C C
fonte
Respostas:
Mathematica
A lista de tamanhos da bacia pode ser obtida por
Onde
m
estão os dados de entrada fornecidos. Para exibir uma matriz como as da pergunta, pode-se substituir// Reverse@Sort@Part[Tally[Flatten@#], All, 2] &
por/. {1 -> "A", 2 -> "B", 3 -> "C"} // MatrixForm
uma ou pode exibi-la como uma imagem em vez de usar//ImageAdjust//Image
.fonte
JavaScript - 673
707730751e=[],g=[],h=[],m=[],q=[];function r(){a=s,b=t;function d(d,A){n=a+d,p=b+A;c>e[n][p]&&(u=!1,v>e[n][p]&&(v=e[n][p],w=n,k=p))}c=e[a][b],u=!0,v=c,w=a,k=b;0!=a&&d(-1,0);a!=l&&d(1,0);0!=b&&d(0,-1);b!=l&&d(0,1);g[a][b]=w;h[a][b]=k;return u}function x(a,b,d){function c(a,b,c,k){g[a+b][c+k]==a&&h[a+b][c+k]==c&&(d=x(a+b,c+k,d))}d++;0!=a&&c(a,-1,b,0);a!=l&&c(a,1,b,0);0!=b&&c(a,0,b,-1);b!=l&&c(a,0,b,1);return d}y=$EXEC('cat "'+$ARG[0]+'"').split("\n");l=y[0]-1;for(z=-1;z++<l;)e[z]=y[z+1].split(" "),g[z]=[],h[z]=[];for(s=-1;s++<l;)for(t=-1;t++<l;)r()&&m.push([s,t]);for(z=m.length-1;0<=z;--z)s=m[z][0],t=m[z][1],q.push(x(s,t,0));print(q.sort(function(a,b){return b-a}).join(" "));
Resultados do teste (usando Nashorn):
Provavelmente haveria problemas de pilha para mapas de tamanho 5000 (mas esse é um detalhe da implementação :).
A fonte não minificada em toda a sua fugacidade:
Consegui melhores resultados de minimização dividindo os objetos do elemento em matrizes separadas, globalizando sempre que possível e adotando efeitos colaterais. NSFW.
Os efeitos da minimização de código:
Eu poderia ter alcançado quase 700 bytes sem editar o código minimizado se estivesse disposto a modificar a fonte original. Mas não o fiz porque acho que deixá-lo como está é uma visão interessante desde o ponto de partida.
fonte
var e=[],g=[],h=[],l,m=[],q=[]
parae=g=h=l=m=q=[]
. Você provavelmente também pode se livrar de outros usos davar
palavra-chave se não estiver sombreando nenhuma variável global.Python: 276
306 365bytesEsta é a minha primeira tentativa de golfe. Sugestões são apreciadas!
editar: as importações e os arquivos de fechamento têm muitos caracteres! O mesmo acontece com o armazenamento de arquivos em variáveis e a compreensão de listas aninhadas.
totalmente comentado (2130 bytes ...)
fonte
open('a').read()
, eu acho.JavaScript (ECMAScript 6) - 226 caracteres
Explicação
Versão anterior - 286 caracteres
Assume que a entrada está em uma variável
S
;Explicação
Teste
Saídas:
[7, 2]
Saídas:
[11, 7, 7]
Saídas:
[5, 7, 4]
fonte
Julia, 315
Apenas uma função recursiva que determina que a célula atual é um coletor ou encontra o dreno, então chame isso em todos os conjuntos de índices. Não me incomodei em fazer a parte de entrada, já que eu não ia ganhar de qualquer maneira, e essa parte não é divertida.
fonte
Haskell, 271
286Ainda pode haver algum código para ser jogado aqui.
Explicação
Ideia básica: para cada célula (i, j), encontre a célula mais baixa na "vizinhança". Isso fornece um gráfico [ (i, j) → (mi, mj) ]. Se uma célula é a célula mais baixa, então (i, j) == (mi, mj) .
Este gráfico pode ser iterado: Para cada a → b no gráfico, substitua-o por a → c onde b → c está no gráfico. Quando essa iteração não gera mais alterações, cada célula no gráfico aponta para a célula mais baixa para a qual ela fluirá.
Para resolver isso, várias alterações foram feitas: Primeiro, as coordenadas são representadas como uma lista de comprimento 2, em vez de um par. Segundo, uma vez que os vizinhos foram encontrados, as células são representadas pelo seu índice em uma matriz linear das células, não nas coordenadas 2D. Terceiro, como existem n * n células, após n * n iterações, o gráfico deve ser estável.
Ungolf'd
fonte
Ruby, 216
É uma abordagem um pouco diferente, apenas invocando "fluxo" em cada quadrado uma vez (o desempenho depende do desempenho do Array :: index). Ele vai da elevação mais alta para a mais baixa, esvaziando uma célula por vez no vizinho mais baixo e marcando a célula como concluída (adicionando 1 à elevação) quando terminar.
Comentado e espaçado:
Changelog:
216 - melhor maneira de desmarcar índices fora dos limites
221 - acontece que "11" vem antes de "2" ... reverter para
to_i
, mas economizar espaço em nossogets
es.224 - Por que declarar
s
, afinal? Eeach
=>map
229 - golfe massivo - classifique as elevações primeiro
s
(e, assim, solte awhile
cláusula), use emmin_by
vez desort_by{...}[0]
, não se preocupeto_i
com elevações, usoflat_map
e encolherselect{}
blocos271 - moveu o tamanho da bacia para nova matriz e usou sort_by
315 - moveu os resultados para uma matriz que dava todos os tipos de benefícios e reduziu a listagem de índices de vizinhos. também ganhou um caractere no índice lambda.
355 - primeiro commit
fonte
Python -
470 447 445 393 392 378 376 375 374369 bytesEu não consigo me parar!
Não é uma solução vencedora, mas me diverti muito criando-a. Esta versão não pressupõe que a entrada seja armazenada em qualquer lugar e, em vez disso, a lê de stdin. Profundidade máxima de recursão = maior distância entre um ponto e o coletor.
Não tenho tempo para explicá-lo hoje, mas aqui está o código não destruído:Na verdade, é bem diferente do código original. Eu li linhas S do stdin, dividi, mapeei para ints e aplainou as listas para obter o campo achatado. Depois, percorro todos os blocos (deixe-me chamá-los de blocos) uma vez. A função de fluxo verifica as peças vizinhas e escolhe aquela com o menor valor. Se for menor que o valor do bloco atual, vá para ele e recorra. Caso contrário, o bloco atual é um coletor e uma nova bacia é criada. O valor de retorno da recursão é o id da bacia.
fonte
JavaScript (ES6) 190
203Editar Um pouco mais de ES6ish (1 ano depois ...)
Defina uma função com linhas de entrada como uma string, incluindo novas linhas, retorne a saída como string com espaços em branco à direita
fonte
Perl 6,
419404Novas linhas adicionadas para maior clareza. Você pode removê-los com segurança.
Solução antiga:
E, no entanto, sou derrotado pelas soluções Python e JavaScript.
fonte