Quão iluminada é esta montanha? 🔥

62

Uma montanha é definida como um conjunto de segmentos de linha cujo primeiro ponto possui coordenadas (0,a)onde a > 0e cujo último ponto possui coordenadas (b,0)onde b > 0. Todos os pontos intermediários têm uma coordenada y (ordenada) estritamente maior que 0. Você recebe os pontos na montanha classificados em ordem crescente da coordenada x (abcissa). Observe que dois pontos podem ter a mesma coordenada x, produzindo um segmento vertical da montanha. Se você receber dois pontos com a mesma coordenada x, eles deverão ser conectados na ordem em que são dados. Além disso, pode haver segmentos horizontais da montanha. Esses segmentos horizontais não estão acesos, não importa o quê. Todas as coordenadas são números inteiros não negativos.

A pergunta: qual é o comprimento total da montanha que seria iluminada, supondo que o sol seja um plano vertical infinito de luz localizado à direita da montanha? Esse número não precisa ser arredondado, mas se for arredondado, inclua pelo menos quatro casas decimais. Incluí uma figura: A montanha Aqui, as linhas em negrito representam os segmentos acesos. Observe que, na entrada, P aparece antes de Q (PQ é um segmento de linha vertical), portanto o ponto anterior é conectado a P e não a Q.

Você pode receber informações em qualquer formato razoável, como uma lista de listas, uma única lista, uma string, etc.

Caso de teste:

(0,3000)
(500, 3500)
(2500, 1000)
(5000,5000)
(9000,2000)
(9000,3500)
(10200,0)

Output: 6200.0000

Existem dois segmentos iluminados aqui, como mostrado nesta imagem: Foto do Caso de Teste O primeiro tem comprimento 5000/2 = 2500 e o segundo tem comprimento 3700.

Isso é , então a resposta mais curta em bytes vence.

fraudado
fonte
11
Dica: Ao encontrar o comprimento de um segmento, há três pontos que você precisa considerar: os dois pontos de extremidade e o ponto que está "bloqueando" (na segunda foto, isso seria (9000,3500) que determina o comprimento do segmento 3-4-5, sejam os dois pontos no segmento principal (x1, y1)e, e (x2,y2)o ponto que está "bloqueando" é (x3, y3). Suponha y2 <y3 <= y1. Então o comprimento do segmento é ((y1 - y3)/(y1 - y2))*sqrt((x1 - x2)^2 + (y1 - y2)^2). fórmula de distância, multiplicada pela fração do segmento que é realmente usado.
rig
11
A montanha pode ser horizontal?
user202729
Sim, pode haver segmentos horizontais na montanha. No entanto, ele chegará a 0 em algum momento.
manipulado
11
Mas eles devem estar acesos?
user202729
Eles não estão acesos. A luz, sendo perfeitamente horizontal, só pode correr paralela a eles e nunca atingi-los. Eu editei o problema para esclarecer isso.
manipulado

Respostas:

14

Python 2 ,  134 131 128 124 120 117 109  107 bytes

p=input();s=0
for X,Y in p[1:]:x,y=p.pop(0);n=y-max(zip(*p)[1]);s+=n*(1+((X-x)/(y-Y))**2)**.5*(n>0)
print s

Experimente online!

Recebe entrada como uma lista de tuplas / listas de dois elementos de números de ponto flutuante.

Explicação

y1>y2for(x2,y2)(x1,y1)

Matemática - Que parte do segmento de linha é exposta à luz?

Uma montanha mal desenhada

(x1,y1)ymax(x2,y2)Lx3y1ymax

x3x2x1x3x2x1=y1ymaxy1x3=(y1ymax)(x2x1)y1

L=(y1ymax)2+x32

Juntando as duas fórmulas, chegamos à seguinte expressão, que é o núcleo dessa abordagem:

L=(y1ymax)2+((y1ymax)(x2x1)y1)2
L=(y1ymax)2(1+(x2x1)2y12)

Código - Como funciona?

p=input();s=0                             # Assign p and s to the input and 0 respectively.
for X,Y in p[1:]:                         # For each point (X, Y) in p with the first
                                          # element removed, do:
    x,y=p.pop(0)                          # Assign (x, y) to the first element of p and
                                          # remove them from the list. This basically
                                          # gets the coordinates of the previous point.
    n=y-max(zip(*p)[1])                   # Assign n to the maximum height after the
                                          # current one, subtracted from y.
    s+=n*(1+((X-x)/(y-Y))**2)**.5         # Add the result of the formula above to s.
                                 *(n>0)   # But make it null if n < 0 (if y is not the
                                          # local maxima of this part of the graph).
print s                                   # Output the result, s.

Changelog

  • Gradualmente otimizada a fórmula para fins de golfe.

  • Economizou 1 byte graças ao FlipTack .

  • Salva 2 bytes removendo a condição desnecessária de que y>Y, uma vez que se o máximo local da coordenada Y após o ponto atual subtraído yfor positivo, essa condição será redundante. Infelizmente, isso invalida o golfe do FlipTack.

  • Economizamos 3 bytes alterando um pouco o algoritmo: em vez de ter uma variável de contador, incrementando-a e seguindo a lista, removemos o primeiro elemento a cada iteração.

  • Economizou 8 bytes graças ao ovs ; mudança (x,y),(X,Y)na condição do loop com uma list.pop()técnica.

  • Economizou 2 bytes graças a Ørjan Johansen (otimizou um pouco a fórmula).

Mr. Xcoder
fonte
12

JavaScript, 97 bytes

a=>a.reduceRight(([p,q,l=0,t=0],[x,y])=>[x,y,y>t?(y-t)/(s=y-q)*Math.hypot(x-p,s)+l:l,y>t?y:t])[2]

f=a=>a.reduceRight(([p,q,l=0,t=0],[x,y])=>[x,y,y>t?(y-t)/(s=y-q)*Math.hypot(x-p,s)+l:l,y>t?y:t])[2];
t=[[0, 3000], [500, 3500], [2500, 1000], [5000, 5000], [9000, 2000], [9000, 3500], [10200, 0]];
console.log(f(t));

(5 bytes podem ser salvos, se considerar válida a versão invertida da entrada.)

tsh
fonte
10

APL + WIN, 48 bytes

+/((h*2)+(((h←-2-/⌈\m)÷-2-/m←⌽⎕)×(⌽-2-/⎕))*2)*.5

Solicita uma lista de coordenadas x seguida por uma lista de coordenadas y

Explicação

h←-2-/⌈\m difference between successive vertical maxima viewed from the right (1)

-2-/m←⌽⎕ vertical difference between points (2)

⌽-2-/⎕ horizontal difference between points (3)

As distâncias verticais acesas = he as distâncias horizontais acesas são (3) * (1) / (2). O resto é Pitágoras.

Graham
fonte
Funcionaria +/.5*⍨(h*2)+×⍨((h←-2-/⌈\m)÷-2-/m←⌽⎕)×⌽-2-/⎕?
Kritixi Lithos
Infelizmente a minha versão antiga APL + WIN não tem o operador então eu não posso dizer
Graham
@Cows quack Conseguiu experimentá-lo em uma versão antiga do Dyalog Unicode (v13) e sua sugestão funciona
Graham
6

Rápido , 190 bytes

import Foundation
func f(a:[(Double,Double)]){var t=0.0,h=t,l=(t,t)
a.reversed().map{n in if l.0>=n.0&&n.1>l.1{t+=max((n.1-h)/(n.1-l.1)*hypot(n.0-l.0,n.1-l.1),0)
h=max(n.1,h)}
l=n}
print(t)}

Experimente online!

Explicação

import Foundation                  // Import hypot() function
func f(a:[(Double,Double)]){       // Main function
  var t=0.0,h=0.0,l=(0.0,0.0)      // Initialize variables
  a.reversed().map{n in            // For every vertex in the list (from right to left):
    if l.0>=n.0&&n.1>l.1{          //   If the line from the last vertex goes uphill:
      t+=max((n.1-h)/(n.1-l.1)     //     Add the fraction of the line that's above the
        *hypot(n.0-l.0,n.1-l.1),0) //     highest seen point times the length of the line
                                   //     to the total
      h=max(n.1,h)}                //     Update the highest seen point
    l=n}                           //   Update the last seen point
  print(t)}                        // Print the total
Herman L
fonte
5

Python 2 , 122 120 bytes

k=input()[::-1]
m=r=0
for(a,b),(c,d)in zip(k,k[1:]):
 if d>m:r+=(b>=m or(m-b)/(d-b))*((a-c)**2+(b-d)**2)**.5;m=d
print r

Experimente online!

ovs
fonte
Como podemos pegar uma lista de valores x e uma lista de valores y como duas entradas, tenho certeza de que poderíamos fazer uma lista de coordenadas ao contrário, eliminando a necessidade de [::-1].
Jonathan Allan
3

Python 2 , 89 bytes

M=t=0
for x,y in input()[::-1]:
 if y>M:t+=(y-M)*abs((x-X)/(y-Y)+1j);M=y
 X,Y=x,y
print t

Experimente online!

Toma em uma lista de pares de carros alegóricos. Baseado na solução da ovs .

xnor
fonte
Pense que podemos pegar uma lista inversa (podemos pegar xey como listas separadas), para que você possa largar a [::-1].
Jonathan Allan
1

APL (Dyalog Unicode) , SBCS de 31 bytes

Usa a fórmula de Graham .

Função de prefixo anônimo, tendo 2 × n matriz de dados como argumento correto. A primeira linha contém valores x da direita para a esquerda e a segunda linha os valores y correspondentes.

{+/.5*⍨(×⍨2-/⌈\2⌷⍵)×1+×⍨÷⌿2-/⍵}

Experimente online!

{} Lambda anônima onde está o argumento:

2-/⍵ deltas (lit. pares menos reduções)

÷⌿ΔxΔy (lit. redução de divisão vertical)

×⍨ quadrado (lit. multiplicação selfie)

1+ um adicionado a isso

( Multiplique o seguinte por isso:

  2⌷⍵ segunda linha do argumento (os valores y)

  ⌈\ executando o máximo (altura mais alta alcançada até agora, indo da direita)

  2-/ deltas de (lit. pares a menos redução)

  ×⍨ quadrado (lit. multiplicação selfie)

.5*⍨raiz quadrada (lit. aumente isso para o poder da metade)

+/ soma

Adão
fonte
1

Gelatina , 23 bytes

ṀÐƤḊ_⁸«©0×⁹I¤÷⁸I¤,®²S½S

Um link diádico com uma lista de valores y à esquerda e uma lista dos respectivos valores x à direita (conforme explicitamente permitido pelo OP nos comentários)

Experimente online!

Quão?

A fração de uma seção (inclinada) acesa é a mesma fração que estaria acesa se fosse uma queda vertical. Observe que, como ocorre o quadrado para avaliar os comprimentos das inclinações, as alturas calculadas ao longo do caminho podem ser negativas (também abaixo, as durações das inclinações acesas são calculadas como negativas divididas por negativas).

ṀÐƤḊ_⁸«©0×⁹I¤÷⁸I¤,®²S½S - Link:list, yValues; list, xValues
 ÐƤ                     - for suffixes of the yValues:       e.g. [ 3000, 3500, 1000, 5000, 2000, 3500,    0]
Ṁ                       -   maximum                               [ 5000, 5000, 5000, 5000, 3500, 3500,    0]
   Ḋ                    - dequeue                                 [ 5000, 5000, 5000, 3500, 3500,    0]
     ⁸                  - chain's left argument, yValues          [ 3000, 3500, 1000, 5000, 2000, 3500,    0]
    _                   - subtract                                [ 2000, 1500, 4000,-1500, 1500,-3500,    0]
        0               - literal zero
      «                 - minimum (vectorises)                    [    0,    0,    0,-1500,    0,-3500,    0]
       ©                - copy to the register for later
            ¤           - nilad followed by link(s) as a nilad:
          ⁹             -   chain's right argument, xValues  e.g. [    0,  500, 2500, 5000, 9000, 9000, 10200]
           I            -   incremental differences               [  500, 2000, 2500, 4000,    0, 1200]
         ×              - multiply (vectorises)                   [    0,    0,    0,-6000000, 0,-4200000, 0]
                ¤       - nilad followed by link(s) as a nilad:
              ⁸         -   chain's left argument, yValues        [ 3000, 3500, 1000, 5000, 2000, 3500,    0]
               I        -   incremental differences               [  500,-2500, 4000,-3000, 1500,-3500]
             ÷          - divide (vectorises)                     [    0,    0,    0, 2000,    0, 1200,    0]
                  ®     - recall from the register                [    0,    0,    0,-1500,    0,-3500,    0]
                 ,      - pair (i.e. lit slope [runs, rises])     [[0, 0, 0,    2000, 0,    1200, 0], [0, 0, 0,   -1500, 0,    -3500, 0]]
                   ²    - square (vectorises)                     [[0, 0, 0, 4000000, 0, 1440000, 0], [0, 0, 0, 2250000, 0, 12250000, 0]]            
                    S   - sum (vectorises)                        [  0,   0,   0, 6250000,   0, 13690000,   0]
                     ½  - square root (vectorises)                [0.0, 0.0, 0.0,  2500.0, 0.0,   3700.0, 0.0]
                      S - sum                                     6200.0

Versão monádica de 25 bytes, com uma lista de [x,y]coordenadas:

ṀÐƤḊ_«0
Z©Ṫµ®FI×Ç÷I,DzS½S

Tente este.

Jonathan Allan
fonte
11
A entrada pode ser duas listas de valores. Eu perguntei ao OP há um tempo atrás e eles disseram que está tudo bem .
Sr. Xcoder 31/12/19
Eu sinto que há muitas s e s.
Jonathan Allan
0

Kotlin , 178 bytes

fun L(h:List<List<Double>>)=with(h.zip(h.drop(1))){mapIndexed{i,(a,b)->val t=a[1]-drop(i).map{(_,y)->y[1]}.max()!!;if(t>0)t*Math.hypot(1.0,(a[0]-b[0])/(a[1]-b[1]))else .0}.sum()}

Experimente online!

A parte de testes muito é não golfed :)

Damiano
fonte