Gerçekten benzersiz olan dizileri sayın


9

Bu, benzersiz kümeler oluşturan Count dizilerinin bir takibi . Önemli fark, tekliğin tanımıdır.

Bir Auzunluk dizisi düşünün n. Dizi yalnızca pozitif tamsayılar içerir. Örneğin A = (1,1,2,2). f(A)Boş olmayan bitişik alt dizilerin toplamları kümesi olarak tanımlayalım A. Bu durumda f(A) = {1,2,3,4,5,6}. Üretilecek adımlar f(A) aşağıdaki gibidir:

Alt dizileri Avardır (1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). Onların toplamları 1,1,2,2,2,3,4,4,5,6. Bu nedenle bu listeden aldığınız set {1,2,3,4,5,6}.

Tersine çevrilmiş dizi dışında aynı uzunlukta başka bir dizi yoksa A benzersiz bir dizi çağırırız . Örnek olarak, ancak aynı toplamları üreten başka bir uzunluk dizisi yoktur .Bf(A) = f(B)Af((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}3

Görev

Verilen nve verilen görev, sbu uzunluktaki benzersiz dizilerin sayısını saymaktır. Sen varsayabiliriz sarasındadır 1ve 9. Yalnızca öğelerin belirli bir tamsayı sveya olduğu bir dizi saymanız gerekir s+1. Örneğin s=1, saydığınız diziler yalnızca 1ve içeriyorsa 2. Bununla birlikte, tekliğin tanımı, aynı uzunluktaki diğer herhangi bir diziye göredir. Somut bir örnek olarak [1, 2, 2, 2]bir değil o kadar toplamlarının aynı kümesini verir benzersiz [1, 1, 2, 3].

Bir dizinin tersini ve dizinin kendisini saymalısınız (dizi elbette bir palindrom olmadığı sürece).

Örnekler

s = 1, n = 2,3,4,5,6,7,8,9 için cevaplar:

4, 3, 3, 4, 4, 5, 5, 6

Çünkü s = 1, uzunluk 4'ün benzersiz dizileri

(1, 1, 1, 1)
(2, 1, 1, 2)
(2, 2, 2, 2)

s = 2, n = 2,3,4,5,6,7,8,9 için cevaplar:

4, 8, 16, 32, 46, 69, 121, 177

Benzersiz olmayan bir diziye örnek s = 2:

(3, 2, 2, 3, 3, 3). 

Bu, her ikisiyle de aynı toplamlara sahiptir: (3, 2, 2, 2, 4, 3)ve (3, 2, 2, 4, 2, 3).

s = 8, n = 2,3,4,5,6,7,8,9 için cevaplar:

4, 8, 16, 32, 64, 120, 244, 472

Puan

Belirli için n, kodunuz tüm değerleri için çıkış cevabı gerektiği sdan 1için 9. Skorunuz bunun nbir dakika içinde tamamladığı en yüksek değerdir .

Test yapmak

Kodunuzu ubuntu makinemde çalıştırmam gerekecek, bu nedenle kodunuzu nasıl derleyeceğiniz ve çalıştıracağınız için lütfen mümkün olduğunca ayrıntılı talimatlar ekleyin.

Liderler Sıralaması

  • n = 13 , Haskell'deki Christian Sievers tarafından (42 saniye)

Ne kadar bellek tüketmemize izin verilir?
Black Owl Kai

@BlackOwlKai Makinemde 8GB var, bu yüzden 6GB güvenli mi?
Anush

Örneklerdeki son sayının 427 yerine 472 olması gerektiğini düşünüyorum.
Christian Sievers

@ChristianSievers Teşekkür ederim. Şimdi düzeltildi.
Anush

Nedir s? Neyi temsil ediyor?
Gigaflop

Yanıtlar:


5

Haskell

import Control.Monad (replicateM)
import Data.List (tails)
import qualified Data.IntSet as S
import qualified Data.Map.Strict as M
import qualified Data.Vector.Unboxed as V
import Data.Vector.Unboxed.Mutable (write)
import System.Environment (getArgs)
import Control.Parallel.Strategies

orig:: Int -> Int -> M.Map S.IntSet (Maybe Int)
orig n s = M.fromListWith (\ _ _ -> Nothing) 
               [(sums l, Just $! head l) | 
                   l <- replicateM n [s, s+1],
                   l <= reverse l ]

sums :: [Int] -> S.IntSet
sums l = S.fromList [ hi-lo | (lo:r) <- tails $ scanl (+) 0 l, hi <- r ]

construct :: Int -> Int -> S.IntSet -> [Int]
construct n start set =
   setmax `seq` setmin `seq` setv `seq`
   [ weight r | r <- map (start:) $ constr (del start setlist)
                                           (V.singleton start)
                                           (n-1)
                                           (setmax - start),
                r <= reverse r ]
  where
    setlist = S.toList set
    setmin = S.findMin set
    setmax = S.findMax set
    setv = V.modify (\v -> mapM_ (\p -> write v p True) setlist)
                    (V.replicate (1+setmax) False)

    constr :: [Int] -> V.Vector Int -> Int -> Int -> [[Int]]
    constr m _ 0 _ | null m    = [[]]
                   | otherwise = []
    constr m a i x =
         [ v:r | v <- takeWhile (x-(i-1)*setmin >=) setlist,
                 V.all (V.unsafeIndex setv . (v+)) a,
                 let new = V.cons v $ V.map (v+) a,
                 r <- (constr (m \\\ new) $! new) (i-1) $! (x-v) ]

del x [] = []
del x yl@(y:ys) = if x==y then ys else if y<x then y : del x ys else yl

(\\\) = V.foldl (flip del)

weight l = if l==reverse l then 1 else 2

count n s = sum ( map value [ x | x@(_, Just _) <- M.toList $ orig n s]
                      `using` parBuffer 128 rseq )
  where 
    value (sms, Just st) = uniqueval $ construct n st sms
    uniqueval [w] = w
    uniqueval _   = 0


main = do
  [ n ] <- getArgs
  mapM_ print ( map (count (read n)) [1..9]
                    `using` parBuffer 2 r0 )

origFonksiyon uzunluktaki tüm listeleri oluşturur ngirişlerle sveya s+1onların tersten önce kendi alt listesini hesaplar gelirse tutar, sumsve koyar da listenin ilk elemanını hatırlayan bir harita olanlar. Aynı toplamlar kümesi bir kereden fazla bulunduğunda, ilk elemanın yerini alır Nothing, bu nedenle bu toplamları elde etmek için başka yollar aramamız gerekmediğini biliyoruz.

constructAlt liste toplamlarının belirli bir kümesine sahip fonksiyonu belirli bir uzunluğun listeleri arar ve Belirlenmiş bir başlangıç değer. Onun özyinelemeli bölüm constresasen aynı mantık şu bu , ancak geri kalan liste girişleri olması gerekir toplamını veren ek bir argüman vardır. Bu, mümkün olan en küçük değerler bile bu toplamı elde etmek için çok büyük olduğunda erken durmaya izin verir ve bu da büyük bir performans artışı sağlar. Bu testi daha önceki bir yere (sürüm 2) taşıyarak ve mevcut toplamlar listesini bir Vector(sürüm 3 (kırık) ve 4 (ek doğrulukla)) ile değiştirerek daha büyük iyileştirmeler elde edildi . En son sürüm, bir arama tablosu ile set üyelik testini yapar ve biraz daha sıkılık ve paralelleştirme ekler.

Ne zaman constructalt liste meblağlar verir ve bunun tersi daha küçük bir liste bulmuştur, onu geri dönebilirler, ama biz gerçekten ilgilenen değildir. ()Varlığını belirtmek için geri dönmek neredeyse yeterli olacaktır , ancak iki kez saymamız gerekip gerekmediğini bilmemiz gerekir (çünkü bir palindrom değildir ve asla tersini yapmayacağız). Bu yüzden 1 veya 2'yi weightsonuç listesine koyduk .

Fonksiyon countbu parçaları bir araya getirir. Alt liste toplamlarının her set için (gelen orig) sadece içeren listeleri arasında eşsiz olduğunu sve s+1yerine getirmekte value, bu çağrılar constructile ve uniquevaltek bir sonucu olup olmadığını kontrol eder. Eğer öyleyse, saymamız gereken ağırlık budur, aksi takdirde toplamlar kümesi benzersiz değildi ve sıfır döndürülür. Tembellik nedeniyle, constructiki sonuç bulduğunda duracağını unutmayın .

mainFonksiyon kolları IO ve döngü s1 ila 9.

Derleme ve Çalıştırma

Debian üzerinde bu paketleri ihtiyaç ghc, libghc-vector-devve libghc-parallel-dev. Programı bir dosyaya kaydedin prog.hsve ile derleyin ghc -threaded -feager-blackholing -O2 -o prog prog.hs. Eşsiz dizileri saymak istediğimiz dizi uzunluğunun ./prog <n> +RTS -Nnerede <n>olduğunu çalıştırın .


Bu kod oldukça şaşırtıcı (ve kısa!). Bazı açıklamalar ekleyebilseydiniz eminim ki insanlar ne yaptığınızı anlamak ister.
Anush

Yeni sürümünüz benim için derlenmiyor. Ben olsun bpaste.net/show/c96c4cbdc02e
Anush

Üzgünüm, daha büyük kodu silmek ve yapıştırmak o kadar rahatsız edici ki bazen sadece birkaç satırı elle değiştiriyorum. Tabii ki bir hata yaptım ... Şimdi düzelttim (umarım) ve bu sefer sadece birkaç yüzde daha bir iyileşme ekledim. Diğer değişiklikler çok daha önemliydi.
Christian Sievers
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.