Як освітлена ця гора? 🔥


62

Гора визначається як набір лінійних сегментів , чиї перша точка має координати , (0,a)де це a > 0, і чия остання точка має координати (b,0), де b > 0. Усі проміжні точки мають y-координату (ординату) строго більше 0. Тобі даються точки гори, відсортовані у порядку зростання за x-координатою (абсциса). Зауважте, що дві точки можуть мати однакову x-координату, створюючи вертикальний відрізок гори. Якщо вам надано дві точки з однаковою координатою x, їх слід з'єднати в тому порядку, в якому вони задані. Крім того, можуть бути горизонтальні відрізки гори. Ці горизонтальні відрізки не освітлені, незалежно від того. Усі координати є невід’ємними цілими числами.

Питання: яка загальна довжина гори, яка була б освітлена, якщо припустити, що сонце - це нескінченна вертикальна площина світла, розташована праворуч від гори? Це число не потрібно округляти, але якщо воно округлене, включайте принаймні чотири знаки після коми. Я включив малюнок: Гори Тут шрифти, виділені жирними лініями, представляють освітлені сегменти. Зауважте, що на вході P з'являється перед Q (PQ - вертикальний відрізок лінії), тому попередня точка підключена до P, а не Q.

Ви можете приймати дані у будь-якому розумному форматі, як список списків, єдиний список, рядок тощо.

Тестовий випадок:

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

Output: 6200.0000

Тут є два освітлені сегменти, як показано на цьому зображенні: Pic тестовий кейс Перший має довжину 5000/2 = 2500, а другий - довжину 3700.

Це , тому найкоротша відповідь у байтах виграє.


1
Підказка: При знаходженні довжини відрізка потрібно враховувати три точки: дві кінцеві точки та точку, яка "блокує" її (на другому малюнку це було б (9000,3500), яке визначає довжину відрізка 3-4-5. Нехай дві точки на головному відрізку будуть (x1, y1)і (x2,y2). Точка, яка "блокує" це, (x3, y3)припустимо, y2 <y3 <= y1. Тоді довжина відрізка дорівнює ((y1 - y3)/(y1 - y2))*sqrt((x1 - x2)^2 + (y1 - y2)^2). Це, по суті, відстань формула, помножене на частку сегмента , який фактично використовується.
фальсифіковані

1
Чи може гора бути горизонтальною?
користувач202729

Так, на горі можуть бути горизонтальні відрізки. Однак в якийсь момент воно перейде до 0.
сфальсифіковано

1
Але чи повинні вони запалюватися?
користувач202729

Вони не запалюються. Світло, будучи ідеально горизонтальним, може лише бігати паралельно їм і ніколи не вражати їх. Я відредагував проблему, щоб уточнити це.
сфальсифікований

Відповіді:


14

Python 2 ,  134 131 128 124 120 117 109  107 байт

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

Спробуйте в Інтернеті!

Приймає введення як список кортежів / двоелементних списків чисел з плаваючою комою.

Пояснення

В основному ми повторюємо через пари точок на графіку, і якщо , то обчислюємо, яка частина лінії піддається впливу світла. Парна ітерація виконується циклом, щоб отримати наступну точку , щоразу вискакуючи перший елемент у списку, щоб отримати поточну точку .y1>y2for(x2,y2)(x1,y1)

Математика - Яка частина відрізка лінії піддається впливу світла?

Погано намальована гора

Нехай - координати поточної точки. Нехай - максимальна висота точки після поточної (локальні максимуми після поточної точки), а - координати наступної точки. Для того, щоб обчислити довжину, виставлену на сонце, , нам слід знайти , як показано на схемі. Природно, якщо , сегмент взагалі не піддається впливу світла.(x1,y1)ymax(x2,y2)Lx3y1ymax

У трикутнику, що утворився, відрізок довжини паралельний основній, довжини , тому всі три кути є конгруентними. Тому з фундаментальної теореми подібності (випадок «Кут-Кут») можна зробити висновок, що . Отже, . Тоді ми можемо застосувати теорему Піфагора, щоб виявити, що:x3x2x1x3x2x1=y1ymaxy1x3=(y1ymax)(x2x1)y1

L=(y1ymax)2+x32

Об’єднавши дві формули, ми доходимо до наступного виразу, що є сутністю цього підходу:

L=

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

Код - Як це працює?

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.

Журнал змін

  • Поступово оптимізували формулу для цілей гольфу.

  • Збережено 1 байт завдяки FlipTack .

  • Збережено 2 байти, видаливши непотрібну умову y>Y, оскільки, якщо локальні максимуми Y -координати після віднімання поточної точки yє позитивними, то ця умова є зайвою. Але, на жаль, це недійсне для гольфу FlipTack.

  • Збережено 3 байти, трохи змінивши алгоритм: замість того щоб мати змінну лічильника, збільшивши її та підкресливши список, ми видаляємо перший елемент при кожній ітерації.

  • Збережено 8 байт завдяки ovs ; зміна (x,y),(X,Y)стану петлі list.pop()технікою.

  • Збережено 2 байти завдяки Ørjan Johansen (трохи оптимізував формулу).


12

JavaScript, 97 байт

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 байт може бути збережено, якщо прийняття зворотної версії введення вважається дійсним.)


10

APL + WIN, 48 байт

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

Запрошує список x координат, а потім список y координат

Пояснення

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)

Запалені вертикальні відстані = h, а освітлені горизонтальні відстані - (3) * (1) / (2). Решта - Піфагор.


Було б +/.5*⍨(h*2)+×⍨((h←-2-/⌈\m)÷-2-/m←⌽⎕)×⌽-2-/⎕працювати?
Kritixi Lithos

На жаль, у моїй старій версії APL + WIN немає оператора, тому я не можу сказати
Грем

@Cows quack Вдалося спробувати його у старій версії Dyalog Unicode (v13), і ваша пропозиція спрацює
Грем

6

Свіфт , 190 байт

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)}

Спробуйте в Інтернеті!

Пояснення

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

5

Python 2 , 122 120 байт

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

Спробуйте в Інтернеті!


Оскільки нам дозволяється приймати список значень x та список значень y як два входи, я впевнений, що ми могли взяти список координат у зворотному порядку, усунувши необхідність [::-1].
Джонатан Аллан

2

Python 2 , 89 байт

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

Спробуйте в Інтернеті!

Бере у списку пар плавців. На основі рішення ovs .


Подумайте, ми можемо взяти зворотний список (нам дозволено приймати x і y як окремі списки), тож ви можете скинути цей [::-1].
Джонатан Аллан

1

APL (Dyalog Unicode) , 31 байт SBCS

Використовує формулу Грема .

Функція анонімного префікса, яка приймає матрицю даних 2 × n як правильний аргумент. Перший рядок містить x-значення справа наліво, а у другому рядку відповідні y-значення.

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

Спробуйте в Інтернеті!

{} Анонімний лямбда, де аргумент:

2-/⍵ дельти (літ. попарно мінус-зменшення)

÷⌿ΔxΔy (зменшення вертикального поділу)

×⍨ квадрат (літ. selfie множення)

1+ один додав до цього

( Помножте на це:

  2⌷⍵ другий рядок аргументу (значення y)

  ⌈\ максимум бігу (найвища висота, яку досі виконували, йде справа)

  2-/ дельти (літ. попарно мінус зменшення)

  ×⍨ квадрат (літ. selfie множення)

.5*⍨квадратний корінь (літ підняти це до сили половини)

+/ сума


1

Желе , 23 байти

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

Діадичне посилання, що містить список значень y зліва та перелік відповідних значень x праворуч (як явно дозволено ОП у коментарях)

Спробуйте в Інтернеті!

Як?

Частка (похилої) секції, що запалюється, - це та сама частка, яка була б освітлена, якби вона була вертикальною краплею. Зауважте, що оскільки проводиться квадратування для оцінки довжин схилу, обчислені висоти по дорозі можуть бути негативними (також у нижній частині довжини прогонів освітлених схилів обчислюються як негативні, поділені на від’ємні).

ṀÐƤḊ_⁸«©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

25-байтна монадійна версія, що містить список [x,y]координат:

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

Спробуйте це.


1
Вхід може бути двома списками значень. Я попросив ОП деякий час тому, і вони сказали, що це добре .
Містер Xcoder

Я відчуваю, що занадто багато s і s.
Джонатан Аллан

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.