Quando as balas colidem

16

Esse desafio se baseia em uma charada que li em algum livro há um tempo atrás, que encontrei novamente aqui . Trata-se de balas disparadas de uma arma uma vez por segundo em velocidades variadas que viajam em linha reta para sempre. Quando uma bala atinge a outra, ambas são destruídas completamente. (Sinta-se à vontade para substituir todas as instâncias de "bala" por "míssil".)

A tarefa

Dada uma lista de velocidades da bala na ordem em que são disparadas, determine se todas as balas foram destruídas.

As regras

  • Entrada é uma lista de números inteiros não negativos, separados por qualquer delimitador e com um caractere opcional antes e depois. Estas são entradas válidas: 1 2 3 4 5 6e [1,2,3,4,5,6]. O programador faz a escolha.
  • Produza um valor verdadeiro se pelo menos uma bala sobreviver para sempre e, caso contrário, um valor falso.
  • As velocidades da bala são dadas em unidades por segundo.
  • As balas se movem simultaneamente e continuamente.
  • As balas podem colidir com compensações fracionárias.
  • Múltiplas balas que atingem simultaneamente a mesma posição, seja em um deslocamento integral ou fracionário da origem, colidem umas com as outras.

Exemplos

Nestes diagramas, Grepresenta a arma, >as balas e *são momentos em que as balas colidem e explodem.

Truthy

Entrada: 0

        0123456789
Time 0 G>
     1 G>
     2 G>
   ...

Resultado: 1


Entrada: 0 0 0

        0123456789
Time 0 G>
     1 G*
     2 G>
     3 G>
     4 G>
   ...

Resultado: 1


Entrada: 1

        0123456789
Time 0 G>
     1 G >
     2 G  >
     3 G   >
   ...

Resultado: 1


Entrada: 2 1

        0123456789
Time 0 G>
     1 G> >
     2 G >  >
     3 G  >   >
     4 G   >    >
   ...

Resultado: 1


Entrada: 2 3 1

        0123456789
Time 0 G>
     1 G> >
     2 G>  >>
     3 G >    *
     4 G  >
     5 G   >
   ...

Resultado: 1


Falsy

Entrada: 1 2 3 4 5 6

        Unit      1111111111
        01234567890123456789
Time 0 G>
     1 G>>
     2 G> *
     3 G>  >
     4 G>   > >
     5 G>    >  >>
     6 G      >   > *
     7 G            >  >
     8 G                  > >
     9 G                        >>
    10 G                              *
                  111111111122222222223
        0123456789012345678901234567890

Resultado: 0


Entrada: 1 0 0 3

        Unit
        0123456789
Time 0 G>
     1 G>>
     2 G* >
     3 G>  >
     4 G   >>
     5 G     *

(A segunda colisão é no momento 4,5)
Saída:0


Entrada: 2 1 2 3 6 5

        Unit      1111111111
        01234567890123456789
Time 0 G>
     1 G> >
     2 G>>  >
     3 G> *   >
     4 G>  >    >
     5 G>     *   >
     6 G     >      >
     7 G          >   >
     8 G               >>
     9 G                *
                  1111111111
        01234567890123456789

Resultado: 0


Entrada: 2 3 6

        Unit
        0123456789
Time 0 G>
     1 G> >
     2 G>  >>
     3 G      *

Resultado: 0

El'endia Starman
fonte
posso exigir que a entrada seja delimitada como 1<enter>2<enter>3...?
gato
@ sysreq: Isso está pressionando, mas eu permitirei.
El'endia Starman
Concordo com qunitopia - este desafio é mau difícil, mas eu estou trabalhando em uma solução ...
zmerch

Respostas:

4

Python 2, 388 392 388 346 342 336 331 bytes

z=k=input();l=len(k);v=range;u=v(l)
while l<z:
 r="";o=[r]*l;z=l
 for h in v(l):
    if r:o[h-1]=o[m]=r;m=h;r=""
    for j in v(h+1,l):
     p=k[h];q=k[j];t=u[j];n=(1.0*q*t-p*u[h])/(q-p)if q-p else""if p>0 else t
     if t<=n<r<()>o[j]>=n<=o[h]:r=n;m=j
 i=0;s=o and min(o)
 while i<l:
    if o[i]==s!="":del k[i],o[i],u[i];l-=1
    else:i+=1
print l

Meu Deus, essa coisa é enorme, mas acredito que realmente funciona. Depois de ver todos os meandros, esse desafio é ridiculamente difícil.

Não tenho certeza se posso explicar como funciona em detalhes sem digitar por horas, por isso darei um resumo executivo.

O grande laço while principal fica em loop até a lista de entradas não encolher.

O loop aninhado for (você pode acreditar que um loop aninhado for realmente o mais curto aqui?) Faz um loop sobre a velocidade de cada marcador e usa-o numpy.rootspara calcular os cálculos em que momento esse marcador colidirá com cada marcador que vem depois. Aqui, ""está sendo usado para significar infinito (sem interseção). Um condicional extra deve ser incluído para garantir que os marcadores interrompidos sejam marcados como colidindo no momento em que aparecem, e não no tempo zero.

Para cada número, controlamos qual marcador ele atingirá o mais rápido, se houver, e oserá atualizado com os tempos mínimos de colisão para os marcadores envolvidos.

Depois que esse loop duplo termina, iteramos sobre a lista de entradas e excluímos qualquer marcador que colidirá no mínimo de todos os tempos de colisão, se houver. Isso nos permite excluir simultaneamente um grande número de marcadores se todos colidirem no mesmo momento.

Em seguida, repetimos todo o processo nas balas restantes, pois elas podem conseguir agora que as balas com as quais teriam colidido foram destruídas.

Assim que nenhum marcador for excluído (indicado pela lista não diminuindo), escapamos do loop while e imprimimos o comprimento da lista restante. Portanto, esse programa não apenas imprime verdade se as balas sobrevivem, mas na verdade imprime exatamente o número de balas que sobrevivem.

EDIT: Agradecimentos especiais ao feersum por gerar casos de teste para me ajudar a encontrar bugs.

EDIÇÃO 2: salvou 42 bytes resolvendo manualmente a equação linear em vez de usar numpy e dividindo os horários de início em uma lista separada e reestruturando uma condicional.

EDIT 3: salvou 4 bytes renomeando intervalo

EDIT 4: Salva mais 6 bytes substituindo espaços duplos por tabulações. Além disso, feersum teve a gentileza de fornecer sua implementação usando frações e conjuntos para comparação. Eu joguei um pouco e ele sai para 331 bytes, amarrando minha solução.

EDIÇÃO 5: salvou 5 bytes removendo uma inicialização desnecessária e reescrevendo uma condição

quintopia
fonte
Você não testou as entradas de exemplo novamente? [1, 0, 0, 3] não funciona.
precisa saber é
@feersum que foi o único que não testei, dangit. mas fixo. COM TUDO ESTE ESFORÇO, MELHOR OBTENDO UM AVALIAÇÃO. : P
quintopia 08/12/2015
Ainda não funciona. [1, 16, 18, 20, 30] deve retornar 1.
feersum
OK, parece funcionar agora, na maioria das vezes, pelo menos.
precisa saber é