Maksimum balta + b bulun


14

Size ( a, b ) listesi ve x listesi verilir . Her x için maksimum baltayı + b hesaplayın . A , b ve x öğelerinin negatif olmayan tamsayı olduğunu varsayabilirsiniz .

Programınızın veya işlevinizin beklenen şekilde çalışması gerekir (kodunuz girdi içermiyorsa rasgeleliğe göre) O ( n log n ) süresi, burada n toplam girdi uzunluğudur (her iki listenin toplam uzunluğu veya toplamı).

Bu kod golfü. En kısa kod kazanır.

Misal

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

Çıktı:

[11 12 14 16 20]

Açıklama:

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

Karmaşıklık hakkında not:

İyi bir ortalama vaka karmaşıklığına sahip bir yerleşik kullandıysanız ve teoride beklenen karmaşıklığı kolayca elde etmek için rastgele seçilebilirseniz, dilinizin bunu yaptığını varsayabilirsiniz.

Bu, programınızın O ( n log n ) içinde, muhtemelen dilinizin uygulanması nedeniyle kenar durumu istisnaları dışında test edilebileceği , ancak kendi kodunuzda mantıksal olarak görülemediği anlamına gelirse, bunun O olduğunu söyleyeceğiz ( n günlüğü n ).


Bana beklenen sonuçların olması gerektiği gibi geliyor [11 12 12 15 4]. ???
Bob Jarvis - Monica'ya geri

@BobJarvis İlgili x için ancak + (b, b) listedeki herkes için maksimum balta + b'dir. Örneği daha az yanıltıcı yapacak şekilde değiştirildi.
jimmy23013

toplam giriş uzunluğu = (a, b) çiftinin uzunluğu artı x? dizisinin uzunluğu
Optimize Edici

@Optimizer Doğru.
jimmy23013

Neden mümkün olduğu açıktır O(n log(n))? Referans algoritması sağlayabilir misiniz?
flawr

Yanıtlar:


1

Pyth - 99 98 bayt

Bu @ KeithRandall'ın Python cevabının doğrudan çevirisidir. Kesinlikle çok daha fazla golf olabilir. Yakında bir açıklama yayınlayacağım .

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 yoluyla virgülle ayrılmış iki virgülle ayrılmış liste alır.

Burada deneyin

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

Python, 214 bayt

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

Dışbükey gövdeyi girdiden a,bartan asırayla yineleyerek hesaplar . Dışbükey kaydedilir Hbiçimi kullanarak X kesişme koordinat ve .-1,0,x1,a1,b1,x2,a2,b2,x2,...,xn,an,bnxia{i-1},b{i-1}ai,bi

Sonra ben girdim xkadar devam etmek için dışbükey gövde keserek, sıralı sırayla s yinelemek .

O (n lgn) türler hariç her şey doğrusaldır.

Gibi çalıştırın:

>>> 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: sabit
Keith Randall

@KeithRandall Son adımda, Hher xgiriş için doğrusal olarak arama Xyaparsınız, değil mi? Her iki liste de aynı uzunlukta olduğunda O (n ^ 2) karmaşıklığına sahip olmak mümkün değil mi?
15'te coredump

1
@coredump: HHer biri için doğrusal olarak arama xyapıyorum, ancak xsırayı yaptığım için son aramanın nerede durduğunu hatırladığım ve bir sonraki aramayı orada başlattığım için. Böylece, iç whiledöngü, en fazla O (n) kez x(herhangi bir kişi için O (n) kez yürütebilse de) çalışabilir x.
Keith Randall

@coredump: whileİlk fordöngüdeki iç döngü için de aynı şeyin gerçekleştiğini unutmayın .
Keith Randall

@KeithRandall Bunu kaçırdım, teşekkürler. Zeki!
15'te coredump

6

Haskell, 204271 bayt

Düzenleme : dışbükey gövde bir liste olarak güncellenir (ancak ungolfed sürümü ile aynı karmaşıklığı ile), "splitLookup x" yerine "split (x + 1)" kullanarak ve Predule gibi tüm nitelikli işlev çağrıları kaldırarak daha fazla golf. foldl.

Bu , (a, b) çiftlerinin listesini ve x değerlerinin bir listesini bekleyen f işlevini oluşturur . Aynı fikirleri kullanarak APL ailesindeki herhangi bir şey tarafından uzunca bir süre içinde uçacak sanırım, ama işte gidiyor:

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

Örnek kullanım:

[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) zamanında çalışır; analiz için aşağıya bakınız.

Düzenleme: İşte big-O analizi ve nasıl çalıştığının bir açıklaması ile ungolfed versiyonu:

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

Yaygın Lisp - 648 692

Gerçek bir ikili arama ile.

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

açıklama

Let , n (a, b) 'nin uzunluğu olabilir ve k noktaları uzunluğu.

  • (a, b) a'ya göre sırala , sonra b - O (n.ln (n))
  • yinelenen girişleri a(paralel çizgiler) kaldırın , yalnızca bher zaman diğerinden daha büyük olan maksimumla paralel çizgiyi koruyarak (kavşakları hesaplarken sıfıra bölünmeyi önleriz) - O (n)
  • sonucu sıkıştır - O (n) : sıralı listede ardışık elemanlar (a0, b0) (a1, b1) (a2, b2) olduğunda, (a0, b0) ve (a1, b1 ), (a1, b1) ve (a2, b2) 'den daha büyükse, (a1, b1) güvenle göz ardı edilebilir.
  • (xab) öğelerinin bir listesini oluşturun; burada x , x + b'nin x için maksimum olduğu satır değerine kadar olan değerdir (bu liste önceki adımlar sayesinde x'e göre sıralanmıştır ) - O (n)
  • bu liste verildiğinde, girişi için aralık kontrolü yapan ve maksimum değeri hesaplayan bir lambda oluşturun - ikili ağaç O (n) 'de oluşturulur (bkz. /programming//a/4309901/124319 ). Uygulanacak ikili aramanın O (ln (n)) karmaşıklığı vardır. Örnek girdi ile, aşağıdaki işlevi oluştururuz (bu işlev daha sonra derlenir):

    (LAMBDA (X)
      (IF (< X 4)
          (IF (< X 2)
              (IF (< X -6)
                  (+ (* 0 X) 4)
                  (+ (* 1 X) 10))
              (+ (* 2 X) 8))
          (+ (* 4 X) 0)))
    
  • bu işlevi tüm öğeler için uygula - O (k.ln (n))

Ortaya çıkan karmaşıklık: En kötü senaryoda O ((n + k) (ln n))) .

Toplam girdi sayısı (n + k) için karmaşıklık tahmini sağlayamayız, çünkü k ve n bağımsızdır. Örneğin, n, asimptotik negligeable wrt olan K , bundan sonra, toplam karmaşıklığı olacaktır O (k) .

Ama eğer biz varsayalım k = O (n) , daha sonra ortaya çıkan karmaşıklık olduğunu Ç (n.ln (n)) .

Diğer örnekler

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

Ve neyin hesaplandığını görmek için geri tırnakları hareket ettirirsek, herhangi bir karşılaştırma yapmamız bile gerekmediğini görebiliriz (ilk liste önceden işlendikten sonra):

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

İşte başka bir örnek (bir yorumdan alınmıştır):

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

Etkili fonksiyon:

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

O (log n, n + k), tabii ki içinde , O ((n + k) log (n + k)).
jimmy23013

Hangi tercümanı kullanıyorsunuz? Ideone verir (LIST* A B C R) should be a lambda expression.
jimmy23013

@ user23013 Üzgünüm, unuttum (use-package :optima) (düzenleme ...)
coredump

@ user23013 Korkarım Ideone'nin harici bir kütüphane yüklemesini sağlayamıyorum. Test için, lütfen SBCL'i indirin (ya da belki başka bir tane, ancak sadece SBCL'de test ettim) ve quicklisp'i yükleyin . Sonra indirmek ve yüklemek için (ql: quickload: optima) yapabilirsiniz optima. Son olarak, verdiğim kod değerlendirilebilir olmalıdır.
15'te coredump

(MAPCAR (EVAL (LAMBDA (X) ...Cevabı değerlendiren geri döndü . Orada hata ayıklama kodu bıraktınız mı?
jimmy23013
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.