นับอาร์เรย์ที่ไม่ซ้ำกันจริงๆ


9

นี่คือการติดตามขึ้นไปนับอาร์เรย์ที่ทำให้ชุดไม่ซ้ำกัน ความแตกต่างที่สำคัญคือนิยามของความเป็นเอกลักษณ์

พิจารณาอาร์เรย์ของความยาวA nอาร์เรย์มีจำนวนเต็มบวกเท่านั้น A = (1,1,2,2)เช่น ให้เรากำหนดf(A)เป็นชุดของผลรวมของทุกคนที่ไม่ว่างเปล่า subarrays Aต่อเนื่องกันของ ในกรณีf(A) = {1,2,3,4,5,6}นี้ ขั้นตอนในการผลิตf(A) มีดังนี้:

subarrays ของAreA จำนวนเงินของตนมี(1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2) ชุดที่คุณได้รับจากรายการนี้จึงเป็น1,1,2,2,2,3,4,4,5,6{1,2,3,4,5,6}

เราเรียกอาเรย์ที่A ไม่ซ้ำกันถ้าไม่มีอาเรย์อื่นBที่มีความยาวเท่ากันเช่นนั้นf(A) = f(B)ยกเว้นสำหรับอาเรย์ที่Aกลับด้าน เป็นตัวอย่างf((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}แต่ไม่มีความยาวอื่น ๆ3ที่สร้างชุดของผลรวมเดียวกัน

งาน

งานสำหรับที่กำหนดnและsจะนับจำนวนอาร์เรย์ที่ไม่ซ้ำกันของความยาวนั้น คุณสามารถสรุปได้ว่าsอยู่ระหว่างและ1 9คุณจะต้องนับอาร์เรย์ที่องค์ประกอบที่มีทั้งจำนวนเต็มรับหรือs s+1เช่นถ้าs=1อาร์เรย์ที่คุณกำลังนับเพียง แต่มีและ1 2อย่างไรก็ตามคำจำกัดความของความเป็นเอกลักษณ์นั้นเกี่ยวข้องกับอาเรย์อื่นที่มีความยาวเท่ากัน ในฐานะที่เป็นตัวอย่างที่เป็นรูปธรรม[1, 2, 2, 2]คือไม่[1, 1, 2, 3]ซ้ำกันที่จะให้ชุดเดียวกันของผลรวมเป็น

คุณควรนับการย้อนกลับของอาเรย์รวมทั้งอาเรย์ด้วยตัวเอง

ตัวอย่าง

s = 1คำตอบสำหรับ n = 2,3,4,5,6,7,8,9 คือ:

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

สำหรับs = 1อาร์เรย์ที่เป็นเอกลักษณ์ของความยาว 4 คือ

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

s = 2คำตอบสำหรับ n = 2,3,4,5,6,7,8,9 คือ:

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

ตัวอย่างของอาร์เรย์ที่ไม่ซ้ำกันs = 2คือ:

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

นี้มีชุดเดียวกันของผลรวมเป็นทั้งสอง: และ(3, 2, 2, 2, 4, 3)(3, 2, 2, 4, 2, 3)

s = 8คำตอบสำหรับ n = 2,3,4,5,6,7,8,9 คือ:

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

คะแนน

สำหรับรับnรหัสของคุณควรเอาท์พุทคำตอบสำหรับทุกค่าของsจากไป1 9คะแนนของคุณคือมูลค่าสูงสุดnซึ่งจะเสร็จสมบูรณ์ในหนึ่งนาที

การทดสอบ

ฉันจะต้องเรียกใช้รหัสของคุณบนเครื่องอูบุนตูของฉันดังนั้นโปรดระบุคำแนะนำโดยละเอียดที่สุดเท่าที่จะทำได้เพื่อรวบรวมและเรียกใช้รหัสของคุณ

ลีดเดอร์บอร์ด

  • n = 13โดย Christian Sievers ในHaskell (42 วินาที)

เราอนุญาตให้ใช้หน่วยความจำเท่าไหร่
Black Owl Kai

@BlackOwlKai เครื่องของฉันมี 8GB ฉันคิดว่า 6GB ปลอดภัยหรือไม่
Anush

ฉันคิดว่าตัวเลขสุดท้ายในตัวอย่างควรเป็น 472 แทนที่จะเป็น 427
Christian Sievers

@ChristianSievers ขอบคุณ แก้ไขแล้ว
Anush

คือsอะไร มันหมายถึงอะไร
Gigaflop

คำตอบ:


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 )

origฟังก์ชั่นสร้างรายชื่อทั้งหมดของความยาวnกับรายการsหรือs+1ช่วยให้พวกเขาหากพวกเขามาก่อนที่จะย้อนกลับของพวกเขาคำนวณรายการย่อยของพวกเขาsumsและทำให้ผู้ที่อยู่ในแผนที่ซึ่งยังจำได้ว่าองค์ประกอบแรกของรายการ เมื่อพบผลรวมชุดเดียวกันมากกว่าหนึ่งครั้งองค์ประกอบแรกจะถูกแทนที่ด้วยNothingดังนั้นเราจึงรู้ว่าเราไม่ต้องมองหาวิธีอื่นในการรับผลรวมเหล่านี้

constructฟังก์ชันการค้นหารายการที่มีความยาวที่กำหนดและได้รับค่าเริ่มต้นที่มีการรับชุดของผลรวมรายการย่อย ส่วน recursive ใช้constrต่อไปนี้เป็นหลักตรรกะเดียวกับนี้แต่มีอาร์กิวเมนต์เพิ่มเติมให้รวมรายการรายการที่เหลือจะต้องมี วิธีนี้ช่วยให้หยุดก่อนได้แม้ว่าค่าที่เล็กที่สุดที่เป็นไปได้นั้นใหญ่เกินไปที่จะได้รับผลรวมนี้ซึ่งทำให้การปรับปรุงประสิทธิภาพสูงขึ้นมาก นอกจากนี้ยังได้รับการปรับปรุงขนาดใหญ่เพิ่มเติมโดยการย้ายการทดสอบนี้ไปยังสถานที่ก่อนหน้า (รุ่น 2) และโดยการแทนที่รายการของผลรวมปัจจุบันด้วยVector(รุ่น 3 (แตก)) และ 4 (ด้วยความเข้มงวดเพิ่มเติม) รุ่นล่าสุดทำการทดสอบการเป็นสมาชิกพร้อมกับตารางการค้นหาและเพิ่มความเข้มงวดและการขนานเพิ่มเติม

เมื่อconstructพบรายการที่ให้ผลรวมของรายการย่อยและมีขนาดเล็กกว่าสิ่งที่ตรงกันข้ามก็สามารถส่งคืนได้ แต่เราไม่สนใจจริงๆ มันเกือบจะเพียงพอแล้วที่จะกลับ()ไปเพื่อบ่งบอกการมีอยู่ของมัน แต่เราจำเป็นต้องรู้ว่าเราต้องนับมันสองครั้งหรือไม่ (เพราะมันไม่ใช่ Palindrome และเราจะไม่จัดการกับสิ่งที่ตรงกันข้าม) ดังนั้นเราจึงใส่ 1 หรือ 2 weightลงในรายการผลลัพธ์

ฟังก์ชั่นcountนี้รวมส่วนต่างๆเข้าด้วยกัน สำหรับผลรวมย่อยแต่ละชุด (มาจากorig) ที่ไม่ซ้ำกันในรายการที่มีเพียงsและs+1จะโทรvalueซึ่งโทรconstructและผ่านuniquevalตรวจสอบว่ามีผลลัพธ์เดียวเท่านั้นหรือไม่ ถ้าเป็นเช่นนั้นนั่นคือน้ำหนักที่เราต้องนับมิฉะนั้นชุดของผลรวมจะไม่ซ้ำกันและส่งกลับศูนย์ โปรดทราบว่าเนื่องจากความเกียจคร้านconstructจะหยุดเมื่อพบผลลัพธ์สองรายการ

mainฟังก์ชั่นจับ IO และห่วงของs1-9

รวบรวมและเรียกใช้

ใน Debian นี้ต้องการแพคเกจghc, และlibghc-vector-dev libghc-parallel-devบันทึกโปรแกรมในแฟ้มและรวบรวมมันด้วยprog.hs ghc -threaded -feager-blackholing -O2 -o prog prog.hsเรียกใช้ด้วย./prog <n> +RTS -Nwhere <n>คือความยาวของอาร์เรย์ที่เราต้องการนับอาร์เรย์ที่ไม่ซ้ำกัน


รหัสนี้ค่อนข้างน่าอัศจรรย์ (และสั้น!) หากคุณสามารถเพิ่มคำอธิบายบางอย่างฉันแน่ใจว่าคนชอบที่จะเข้าใจสิ่งที่คุณได้ทำ
Anush

เวอร์ชันใหม่ของคุณไม่ได้รวบรวมสำหรับฉัน ฉันได้รับbpaste.net/show/c96c4cbdc02e
Anush

ขออภัยการลบและวางโค้ดที่ใหญ่กว่านั้นทำให้ฉันรู้สึกอึดอัดที่บางครั้งฉันแค่เปลี่ยนไม่กี่บรรทัดด้วยมือ แน่นอนว่าฉันทำผิดพลาด ... แก้ไขตอนนี้ (ฉันหวังว่า) และเพิ่มการปรับปรุงอีกครั้งคราวนี้เพียงไม่กี่เปอร์เซ็นต์ การเปลี่ยนแปลงอื่น ๆ มีความสำคัญมากกว่า
Christian Sievers
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.