Знайдіть максимум ax ​​+ b


14

Вам надається список ( a, b ) та список x . Обчисліть максимальну ось + b для кожного x . Можна припустити, що а , b і x є невід’ємними цілими числами.

Ваша програма або функція повинна працювати у очікуваному (до випадковості, якщо ваш код передбачає це, а не вхідний) час O ( n log n ), коли n - загальна довжина введення (сума або максимум довжин обох списків).

Це код-гольф. Найкоротший код виграє.

Приклад

[[2 8] [4 0] [2 1] [1 10] [3 3] [0 4]] [1 2 3 4 5]

Вихід:

[11 12 14 16 20]

Пояснення:

11 = 1*1 + 10
12 = 1*2 + 10 = 2*2 + 8
14 = 2*3 + 8
16 = 2*4 + 8 = 4*4 + 0
20 = 4*5 + 0

Примітка про складність:

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

Це означає, що якщо ваша програма може бути перевірена на вміст O ( n log n ), можливо, за винятком кращих регістрів через реалізацію вашої мови, але її неможливо сприймати у власному коді, ми скажемо, що це O ( n журнал n ).


Мені здається, очікувані результати повинні бути [11 12 12 15 4]. ???
Боб Джарвіс - Відновіть Моніку

@BobJarvis Це максимум ax ​​+ b для відповідного x, але для всіх (a, b) у списку. Змінено, щоб зробити приклад менш оманливим.
jimmy23013

загальна довжина вводу = довжина пар (a, b) плюс довжина масиву x?
Оптимізатор

@Optimizer Правильно.
jimmy23013

Чому зрозуміло, що це можливо навіть O(n log(n))? Чи можете ви надати довідковий алгоритм?
flawr

Відповіді:


1

Pyth - 99 98 байт

Це майже прямий переклад відповіді Python @ KeithRandall. Однозначно можна пограти в гольф набагато більше. Я скоро опублікую пояснення .

K[_1Z;FNShQAkdNW&>K2>+*k@K_3d+*@K_2@K_3eK=K<K_3)~K[c-eKd-k@K_2kd;FNSeQW&>K2>N@K2=K>K3)aY+*hKN@K1;Y

Бере два списки з комами, розділені комами через stdin.

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

K                  K=
 [  )              A List containing
  _1               Negative 1
  Z                Zero
FN                 For N in
 ShQ               Sorted first input
Akd                Double assign k and d
 N                 To N
 W                 While
  &                Logical And
   >K2             K>2
   >               Greater Than
    +*k@K_3d       K[-3]*k+d
    +              Plus
     *@K_2@K_3     K[-2]*K[-3]
     eK            K[-1]
  =K               K=
   <K_3            K[:-3]
  )                Close while loop
 ~K                K+=
  [      )         List constructor
   c               Float division
    -              Minus
     eK            K[-1]
     d             d
    -              Minus
     k             k
     @K_2          K[-2]
   k               k
   d               d
 ;                 End list and for loop
FN                 For N in
  SeQ              Sorted second input
  W                While loop
   &               Logical and
    >K2            K[2:]
    >              Greater than
     N             N
     @K2           K[2]
   =K              K=
   >K3             K[3:]
  )                Close while loop
  aY               Y.append - Y is empty list
   +               Plus
    *hKN           (K+1)*N
    @K1            K[1]
;                  Close out everything
Y                  Print Y

10

Пітон, 214 байт

S=sorted
def M(L,X):
 H=[-1,0];R={}
 for a,b in S(L):
    while H[2:]and a*H[-3]+b>H[-2]*H[-3]+H[-1]:H=H[:-3]
    H+=[1.*(H[-1]-b)/(a-H[-2]),a,b]
 for x in S(X):
    while H[2:]and x>H[2]:H=H[3:]
    R[x]=H[0]*x+H[1]
 return R

Обчислює опуклий корпус шляхом ітерації через вхід a,bу aпорядку збільшення . Опуклий корпус записується у Hформаті, -1,0,x1,a1,b1,x2,a2,b2,x2,...,xn,an,bnде xiє координата x перетину a{i-1},b{i-1}та ai,bi.

Тоді я повторюю, хоча вхідний сигнал xв упорядкованому порядку, обрізаючи опуклий корпус, щоб не відставати, як я йду.

Все лінійно, за винятком сортів, які є O (n lgn).

Виконайте це так:

>>> print M([[2,8],[4,0],[2,1],[1,10],[3,3],[0,4]], [1,2,3,4,5])
{1: 11, 2: 12, 3: 14, 4: 16, 5: 20}

@ user23013: виправлено
Кіт Рендалл

@KeithRandall На останньому кроці ви шукаєте Hлінійно для кожного xв X, чи не так ?. Чи не можливо, що ми маємо складність O (n ^ 2), коли обидва списки мають однакову довжину?
coredump

1
@coredump: Я шукаю Hлінійно для кожного x, але тому, що роблю xs, щоб запам'ятати, де зупинився останній пошук, і почати наступний пошук там. Таким чином, внутрішній whileцикл може виконувати максимум O (n) разів у всіх x(навіть якщо він може виконати O (n) разів для будь-якої особи x).
Кіт Рендалл

@coredump: Зверніть увагу, що те ж саме відбувається і з внутрішнім whileциклом у першому forциклі.
Кіт Рендалл

@KeithRandall я пропустив це, дякую. Розумний!
coredump

6

Хаскелл, 204 271 байт

Редагувати : гольф набагато далі, оновивши опуклий корпус у списку (але з тією ж складністю, що і версія без вогків), використовуючи "split (x + 1)" замість "splitLookup x" та видаляючи всі кваліфіковані виклики функцій, такі як Predule. скласти.

Це створює функцію f, яка очікує переліку пар (a, b) і список значень x. Я здогадуюсь, що це буде здуто будь-якою мірою у сімействі APL, використовуючи ті самі ідеї, але ось це:

import Data.Map
r=fromListWith max
[]%v=[(0,v)]
i@((p,u):j)%v|p>v#u=j%v|0<1=(v#u,v):i
(a,b)#(c,d)=1+div(b-d)(c-a)
o i x=(\(a,b)->a*x+b)$snd$findMax$fst$split(x+1)$r$foldl'(%)[]$r$zip(fmap fst i)i
f=fmap.o

Використання зразка:

[1 of 1] Compiling Main             ( linear-min.hs, interpreted )
Ok, modules loaded: Main.
λ> f [(2,8), (4,0), (2,1), (1,10), (3,3), (0,4)] [1..5]
[11,12,14,16,20]
λ> f [(1,20), (2,12), (3,11), (4,8)] [1..5]
[21,22,23,24,28]

Він працює в O (n log n) час; див. нижче для аналізу.

Редагувати: Ось неперевершена версія з аналізом big-O та описом того, як це все працює:

import Prelude hiding (null, empty)
import Data.Map hiding (map, foldl)

-- Just for clarity:
type X = Int
type Y = Int
type Line = (Int,Int)
type Hull = Data.Map.Map X Line
slope (a,b) = a

{-- Take a list of pairs (a,b) representing lines a*x + b and sort by
    ascending slope, dropping any lines which are parallel to but below
    another line.

    This composition is O(n log n); n for traversing the input and
    the output, log n per item for dictionary inserts during construction.
    The input and output are both lists of length <= n.
--}
sort :: [Line] -> [Line]
sort = toList . fromListWith max

{-- For lines ax+b, a'x+b' with a < a', find the first value of x
    at which a'x + b' exceeds ax + b. --}
breakEven :: Line -> Line -> X
breakEven p@(a,b) q@(a',b') = if slope p < slope q
                                 then 1 + ((b - b') `div` (a' - a))
                                 else error "unexpected ordering"

{-- Update the convex hull with a line whose slope is greater
    than any other lines in the hull.  Drop line segments
    from the hull until the new line intersects the final segment.
    split is used to find the portion of the convex hull
    to the right of some x value; it has complexity O(log n).
    insert is also O(log n), so one invocation of this 
    function has an O(log n) cost.

    updateHull is recursive, but see analysis for hull to
    account for all updateHull calls during one execution.
--}
updateHull :: Line -> Hull -> Hull
updateHull line hull
    | null hull = singleton 0 line
    | slope line <= slope lastLine = error "Hull must be updated with lines of increasing slope"
    | hull == hull' = insert x line hull
    | otherwise = updateHull line hull''
    where (lastBkpt, lastLine) = findMax hull
          x = breakEven lastLine line
          hull' = fst $ x `split` hull
          hull'' = fst $ lastBkpt `split` hull

{-- Build the convex hull by adding lines one at a time,
    ordered by increasing slope.

    Each call to updateHull has an immediate cost of O(log n),
    and either adds or removes a segment from the hull. No
    segment is added more than once, so the total cost is
    O(n log n).
--}
hull :: [Line] -> Hull
hull = foldl (flip updateHull) empty . sort

{-- Find the highest line for the given x value by looking up the nearest
    (breakpoint, line) pair with breakpoint <= x.  This uses the neat
    function splitLookup which looks up a key k in a dictionary and returns
    a triple of:
        - The subdictionary with keys < k.
        - Just v if (k -> v) is in the dictionary, or Nothing otherwise
        - The subdictionary with keys > k.

    O(log n) for dictionary lookup.
--}
valueOn :: Hull -> X -> Y
valueOn boundary x = a*x + b
    where (a,b) = case splitLookup x boundary of
                    (_  , Just ab, _) -> ab
                    (lhs,       _, _) -> snd $ findMax lhs


{-- Solve the problem!

    O(n log n) since it maps an O(log n) function over a list of size O(n).
    Computation of the function to map is also O(n log n) due to the use
    of hull.
--}
solve :: [Line] -> [X] -> [Y]
solve lines = map (valueOn $ hull lines)

-- Test case from the original problem
test = [(2,8), (4,0), (2,1), (1,10), (3,3), (0,4)] :: [Line]
verify = solve test [1..5] == [11,12,14,16,20]

-- Test case from comment
test' = [(1,20),(2,12),(3,11),(4,8)] :: [Line]
verify' = solve test' [1..5] == [21,22,23,24,28]

2

Лист звичайний - 648 692

За допомогою фактичного двійкового пошуку.

(use-package :optima)(defun z(l e)(labels((i(n m)(/(-(cadr m)(cadr n))(-(car n)(car m))))(m(l)(match l((list* a b c r)(if(<(i a b)(i b c))(list* a(m(list* b c r)))(m(list* a c r))))(_ l)))(f(x &aux(x(cdr x)))`(+(*,(car x)x),(cadr x)))(g(s e)(let*((q(- e s))(h(+ s(floor q 2)))d)(if(> q 1)(let((v(g s h))(d(pop l)))`(if(< x,(car d)),v,(g(1+ h)e)))(cond((not(car (setq d (pop l))))(f d))((> q 0)`(if(< x,(car d)),(f d),(f(pop l))))(t(f d)))))))(setq l(loop for(a b)on(m(remove-duplicates(#3=stable-sort(#3# l'< :key'cadr)'< :key'car):key 'car)) by #'cdr collect`(,(when b(i a b)),(car a),(cadr a))))`(mapcar(eval(lambda(x),(g 0(1-(length l)))))',e)))

(z '((2 8) (4 0) (2 1) (1 10) (3 3) (0 4)) '(1 2 3 4 5))
=> (11 12 14 16 20)

Пояснення

Нехай n - довжина (a, b), k - довжина точок.

  • сортувати (a, b) по a, тоді b - O (n.ln (n))
  • видаліть записи для дублікатів a(паралельних рядків), зберігаючи лише паралельну лінію з максимумом b, який завжди більший за інший (ми запобігаємо поділам на нуль при обчисленні перехресть) - O (n)
  • стиснути результат - O (n) : коли у відсортованому списку є елементи послідовності (a0, b0) (a1, b1) (a2, b2), таким чином, що точки перетину (a0, b0) та (a1, b1 ) більше, ніж один з (a1, b1) і (a2, b2), тоді (a1, b1) можна сміливо ігнорувати.
  • скласти список елементів (xab), де x - значення, до якого лінія ax + b є максимальним для x (цей список сортується за x завдяки попереднім крокам) - O (n)
  • з урахуванням цього списку побудуйте лямбда, яка виконує перевірку інтервалу для його введення та обчислює максимальне значення - бінарне дерево вбудовано в O (n) (див. /programming//a/4309901/124319 ). Двійковий пошук, який буде застосовано, має складність O (ln (n)) . На прикладі введення ми будуємо таку функцію (ця функція потім компілюється):

    (LAMBDA (X)
      (IF (< X 4)
          (IF (< X 2)
              (IF (< X -6)
                  (+ (* 0 X) 4)
                  (+ (* 1 X) 10))
              (+ (* 2 X) 8))
          (+ (* 4 X) 0)))
    
  • застосувати цю функцію до всіх елементів - O (k.ln (n))

Результатна складність: O ((n + k) (ln n))) у найгіршому випадку.

Ми не можемо дати оцінку складності для загальної кількості входів (n + k), оскільки k і n є незалежними. Наприклад, якщо n асимптотично незначно wrt k , то загальна складність буде O (k) .

Але якщо припустити, що k = O (n) , то отримана складність - O (n.ln (n)) .

Інші приклади

(z '((1 10) (1 8) (1 7)) '(1 2 3 4 5))
=> (11 12 13 14 15)

І якщо ми перемістимо зворотні котирування, щоб побачити, що обчислюється, ми можемо побачити, що нам навіть не потрібно проводити порівняння (як тільки попередній список буде попередньо оброблений):

(MAPCAR (LAMBDA (X) (+ (* 1 X) 10)) '(1 2 3 4 5))

Ось ще один приклад (взятий із коментаря):

(z '((1 20) (2 12) (3 11) (4 8)) '(1 2 3 4 5))
=> (21 22 23 24 28)

Ефективна функція:

(MAPCAR
  (LAMBDA (X)
    (IF (< X 4)
        (+ (* 1 X) 20)
        (+ (* 4 X) 8)))
  '(1 2 3 4 5))

O (n log n + k) - це звичайно в O ((n + k) log (n + k)).
jimmy23013

Якого перекладача ви використовуєте? Ідеон дає (LIST* A B C R) should be a lambda expression.
jimmy23013

@ user23013 Вибачте, я забув (use-package :optima) (редагування ...)
coredump

@ user23013 Боюся, що я не можу змусити Ideone завантажити зовнішню бібліотеку. Для тестування завантажте SBCL (або, можливо, інший, хоча я протестував лише SBCL) та встановіть quicklisp . Потім ви можете (ql: quickload: optima) завантажити та встановити optima. Нарешті, код, який я надав, повинен бути оцінений.
coredump

Він повернувся, (MAPCAR (EVAL (LAMBDA (X) ...що оцінює відповідь. Ви залишили там код налагодження?
jimmy23013
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.