Share
Embed
Haskell でアルゴリズムを抽象化する / 関数型言語で競技プログラミング
Competitive programming with Haskell
Functional Festival 2025 in TOKYO
Naoya Ito
June 14, 2025
Transcript
89 slides
-
ࣗݾհ • גࣜձࣾ Ұٳ ϗςϧɺϨετϥϯͷ8FC༧ࣄۀͷձࣾ Ͱಇ͍͍ͯ·͢ • झຯͰڝٕϓϩάϥϛϯάΛᅂΜͰ͓Γɺ)BTLFMMͰࢀઓ͍ͯ͠·͢ • ݱࡏͷϨʔτਫ৭
Ͱ͢ – ڭՊॻʹग़ͯ͘ΔྨͷΞϧΰϦζϜͳ͍͘͜ͳͤΔϨϕϧ -
͍ͨ͜͠ͱ • )BTLFMM ͰڝٕϓϩάϥϛϯάʹࢀՃ͍ͯ͠ΔɻΞϧΰϦζϜΛநԽ͢Δͱɺͦͷ࣮͕ ࣅͨΑ͏ͳΠϯλϑΣʔεʹͳΔ͜ͱΛܦݧͨ͠ – ߴ֊ؔͱͯࣸ͠૾ Gͱ݁߹ͷೋ߲ԋࢉ͕ύϥϝʔλͱͯ͠Α͘දΕΔ • ͦΕۮવͳͷ͔ɺ͍ɺۮવͰͳ͍
– )BTLFMMͷࠜఈʹ͋Δ࠶ؼσʔλߏɺͦΕʹ࠷దͳૢ࡞Ͱ͋Δࣸ૾ͱΈࠐΈ NBQSFEVDF • ࣸ૾ͱΈࠐΈʹΑΔؔͷΠϯλϑΣʔε͔ΒΞϧΰϦζϜͷతߏ͕ݟ͑Δ • ؔܕϓϩάϥϛϯάɺ)BTLFMMΞϧΰϦζϜΛΑΓநߴ͘ଊ͑ΔࢥߟΛิॿͯ͘͠ ΕΔ -
࣍ • ࣸ૾ NBQ ͰΛղ͘ • ྦྷੵ uuu GPMETDBOMʹΑΔʮΈࠐΈʯ •
ΞϧΰϦζϜΛநԽ͢Δ uuu ೋ୳ࡧΛߴ֊ؔͰநԽ͢Δ • #'4ΛநԽ͢Δuuu ؔ GΛʮ͋Δঢ়ଶ͔Β࣍ͷঢ়ଶͷঢ়ଶભҠʯͱଊ͑Δ • ಈతܭը๏Λ )BTLFMMͰΠϛϡʔλϒϧʹղ͘ uuuঢ়ଶۭؒͷΈࠐΈɺͦͯ͠తߏ ͕ݟ͑Δ • ͳͥΞϧΰϦζϜΛநԽ͢ΔͱɺNBQSFEVDF GPME తߏ͕ uuu ؔܕϓϩά ϥϛϯάɺ)BTLFMM͕ͦΕΛଅ͢ -
ࣸ૾ͱ݁߹ ू uuu NBQSFEVDF GPME • ؔܕϓϩάϥϛϯάͰʮࣸ૾ͱ݁߹ ू ʯͷϝϯλϧϞσϧͰΛղ͘ •
ࣸ૾ͱ݁߹ ू uuu NBQSFEVDF GPME • ͳͥ NBQSFEVDF͔ – )BTLFMMͷෆมσʔλߏతσʔλܕʹΑΔ࠶ؼσʔλߏ – ࠶ؼσʔλߏͷૢ࡞ʹ NBQSFEVDF – -*41ͷײ͔Βʜ ͋ͱͰ -
#'4ʹ͍ͯ͠Δؔ GͷҙຯΛߟ͑ͯΈΔ let dist = bfs f (+) (-1) bounds
[(1, 0 :: Int)] • f Λهड़͢Δ͚ͩͰ͕ղ͚Δ͕ɺf Կऀ? • (v -> [(v, e)]) • (ঢ়ଶ -> [(࣍ͷঢ়ଶ, ભҠίετ)]) ͱ͍͏ঢ়ଶભҠͷࣸ૾ ঢ়ଶ͔ΒભҠީิͷࣸ૾ ͱߟ͑Δ͜ͱ͕Ͱ͖Δ -
݁߹ͷํͱঢ়ଶભҠͷؔ ͋ͱॳظঢ়ଶ Λએݴ͢Εɺ%1͕ղ͚Δ main = do [n, wx] <- getInts
items <- replicateM n getTuple let dp = accumArrayDP @UArray f max 0 (0, wx) [(0, 0)] items where f (w, acc) (wi, vi) = [(w, acc), (w + wi, acc + vi)] print $ maximum (elems dp) -
͜Εۮવͳͷ͔ • )BTLFMMͰΞϧΰϦζϜΛநԽ͢Δͱɺ݁߹ ೋ߲ ԋࢉɺࣸ૾ ͋ͱॳظ ঢ়ଶ ͕ύϥϝʔλԽ͞ΕͯΠϯλϑΣʔεʹදΕΔ • NBQSFEVDF
• ͦͯ͠ΠϯλϑΣʔε͕ʮతߏΈʯΛଳͼΔ -
ͳͥͦΕ͕ɺతߏͱ݁ͼͭ͘ͷ͔ • લड़ͷ௨Γ ࠶ؼతσʔλߏࣸ૾ͱ݁߹ʹࣗવʹؐݩͰ͖Δ • ঢ়ଶͷʮൖʯͱʮूʯతੑ࣭Λඞཁͱ͢Δ – ʮൖʯ֤ঢ়ଶΛ৽͍͠ঢ়ଶʹࣸ͢ ˠࣸ૾ –
ʮूʯෳͷ݁ՌΛҰͭʹ·ͱΊΔ ˠ݁߹ – ͜Ε͕݁߹తͰͳ͚Ε࠶ؼɾޮԽ͕͍͠ ˠతߏͷཁ ΞϧΰϦζϜΛநԽ͢Δͱࣸ૾ͱ݁߹͕ܭࢉͷຊ࣭తͳߏཁૉͱͯ͠ݱΕΔ ঢ়ଶۭؒΛू߹ͱΈͳ͢ͱɺతߏʢ'VODUPS .POPJE 4FNJSJOHʣʹରԠ͢Δ )BTLFMMͷܕͱߴ֊ؔɺͦͷߏΛࣗવʹΠϯλϑΣʔεͱͯ͠࿐ग़ͤ͞Δ நԽʮܭࢉͷʯΛՄࢹԽ͢ΔաఔͰ͋Δ -
8 12 40 4 6 20 2 3 10 ۮ͔͠ͳ͍ͷͰૢ࡞͢Δ
·ͩۮ͔͠ͳ͍ͷͰૢ࡞͢Δ ح͕ग़͖ͯͨͷͰऴΘΓ -
໋ྩܕϓϩάϥϛϯάͰ࣮ uuu ໋σʔλߏΛ܁Γฦ͠ॻ͖͑ͯ͑ΛಘΔ count = 0 while all(a % 2
== 0 for a in as): for i in range(n): as[i] //= 2 count += 1 print(count) -
ؔܕ Ӭଓσʔλϓϩάϥϛϯά ͳΒʮࣸ૾ NBQ Λ܁Γฦ͠ద༻͢Δʯͱߟ͑Δ let res = takeWhile (all
even) $ iterate (map (`div` 2)) as print $ length res -
۠ؒʹྦྷੵΛ͏ͱΑ͍ let ds = [3, 1, 4, 1, 5, 9]
:: [Int] s = scanl' (+) 0 ds -- [0, 3, 4, 8, 9, 14, 23] -
໋ྩతʹ࣮͢Δ p, q = input().split() ds = [3, 1, 4,
1, 5, 9] # 累積和 s = [0] * 7 for i in range(6): s[i + 1] = s[i] + ds[i] pi = ord(p) - ord('A') qi = ord(q) - ord('A') print(abs(s[qi] - s[pi])) -
໋ྩܕ uuu Ұ࣌తͳঢ়ଶΛ܁Γฦ͠ॻ͖͑ͯɺྦྷੵͱ͢Δ # 累積和 s = [0] * 7
for i in range(6): s[i + 1] = s[i] + ds[i] -
ؔܕͰ࣮͢Δ main :: IO () main = do (p, q)
<- auto @(Char, Char) let ds = [3, 1, 4, 1, 5, 9] :: [Int] s = listArray @UArray ('A', 'G') $ scanl' (+) 0 ds ans = s ! q - s ! p print $ abs ans -
݁߹ ͷ࠶ؼతͳؔద༻ uuu ʮΈࠐΈʯ foldl (+) 0 [3, 1, 4,
1, 5, 9] ==> ((((((0 + 3) + 1) + 4) + 1) + 5) + 9) scanl (+) 0 [3, 1, 4, 1, 5, 9] [ 0 , (0 + 3) , ((0 + 3) + 1) , (((0 + 3) + 1) + 4) , ((((0 + 3) + 1) + 4) + 1) , (((((0 + 3) + 1) + 4) + 1) + 5) , ((((((0 + 3) + 1) + 4) + 1) + 5) + 9) ] -
վΊͯ )BTLFMMͰͷྦྷੵ uuu TDBOMΛΈͯΈΔ let ds = [3, 1, 4,
1, 5, 9] :: [Int] s = scanl' (+) 0 ds -- [0, 3, 4, 8, 9, 14, 23 scanl' :: (b -> a -> b) -> b -> [a] -> [b] • ࠶ؼతʹ݁߹Λద༻͢Δɺͱ͍͏ྦྷੵܭࢉ ΈࠐΈ ΛநԽͨ͠ͷ͕ TDBOM • TDBOMͷΠϯλϑΣʔεʹ݁߹ԋࢉ͕ύϥϝʔλͱͯ͠දΕ͍ͯΔ – ͳΒྦྷੵ – NBYͳΒྦྷੵ NBY – NJOͳΒྦྷੵ NJO – YPSͳΒྦྷੵ YPS -
ࣸ૾ͱ݁߹ ू uuu NBQSFEVDF GPME • ؔܕϓϩάϥϛϯάͰʮࣸ૾ͱ݁߹ ू ʯͷϝϯλϧϞσϧͰΛղ͘ •
ࣸ૾ͱ݁߹ ू NBQSFEVDF GPME • ͳͥ NBQSFEVDF͔ – )BTLFMMͷෆมσʔλߏతσʔλܕʹΑΔ࠶ؼσʔλߏ – ࠶ؼσʔλߏͷૢ࡞ʹ NBQSFEVDF – -*41ͷײ͔Βʜ ͋ͱͰ -
୯ௐੑ͕͋ΔͷͰɺڥքΛఆΊΔ͜ͱ͕Ͱ͖Δ Ҏ্ uuu
ճ Ҏ্ uuuճ Ҏ্ uuu ճ Ҏ্ uuuճ Ҏ্ uuu ճ Ҏ্ uuu ճ ͜͜·Ͱ݅Λຬͨ͢ɺҎ߱ຬͨ͞ͳ͍ YҎ্ͷཁૉ͕ YճҎ্දΕΔ͔ -
ೋ୳ࡧͰղ͚·͢ɻͰɺίϯςετதʹೋ୳ࡧΛॻ͘ͱόάΒ͕ͤͪ main :: IO () main = do _ <-
getInt as <- getInts let binSearch (ok, ng) | abs (ng - ok) == 1 = ok | otherwise = do let m = (ok + ng) `div` 2 count = length $ filter (>= m) as if count >= m then binSearch (m, ng) else binSearch (ok, m) print $ binSearch (0, 10 ^ 18) -
ຖճॻ͔ͳ͍͍ͯ͘Α͏ɺநԽ͠·͢ ˠߴ֊ؔ G͕දΕΔ -- | 左が true / 右が false
で境界を引く bisect2 :: (Integral a) => (a, a) -> (a -> Bool) -> (a, a) bisect2 (ok, ng) f | abs (ng - ok) == 1 = (ok, ng) | f m = bisect2 (m, ng) f | otherwise = bisect2 (ok, m) f where m = (ok + ng) `div` 2 let (ok, _) = bisect2 (0, 10 ^ 18) (¥x -> countBy (>= x) as >= x) print ok -
݅ؔ Gࣸ૾ͱΈͳͤΔ • ೋ୳ࡧʮڥքΛҾ݅͘ʯΛؔ GͰ͢Α͏நԽͰ͖Δ • (a -> Bool) Λʮ
͔Β ݅Λຬ͔ͨ͢Ͳ͏͔ͷࣸ૾ʯͱଊ͑Δ͜ͱ͕Ͱ͖Δ • ΞϧΰϦζϜΛநԽͨ͠Βͦ͜ʹࣗવͱࣸ૾ G͕දΕͨ bisect2 :: (Integral a) => (a, a) -> (a -> Bool) -> (a, a) -
άϥϑΛʮྡϦετʯʹߏԽͯ͠ #'4 ෯༏ઌ୳ࡧ ͢Δ main = do [n, m] <-
getInts uvs <- replicateM m getTuple -- 1 => [(2, 1), (4, 1)] という構造の「隣接リスト」にする let g = accumArray @Array (flip (:)) [] (1, n) $ concatMap (¥(u, v) -> [(u, (v, 1)), (v, (u, 1))]) uvs -- 幅優先探索する dist = bfs g [(1, 0)] for_ [1 .. n] $ ¥s -> print $ dist ! s -
ࢀߟ ઌͷ #'4 ͷ࣮ bfs :: (Ix v, IArray a
[(v, e)], Num e, Eq e) => a v [(v, e)] -> [(v, e)] -> Array v e bfs g v0s = runSTArray $ do dist <- newArray (bounds g) (-1) for_ v0s $ ¥(v0, d0) -> do writeArray dist v0 d0 aux (Seq.fromList [v0 | (v0, _) <- v0s]) dist return dist where aux Empty _ = return () aux (v :<| queue) dist = do acc <- readArray dist v us <- filterM ( ¥(u, _) -> (fmap (== -1) . readArray dist) u ) (g ! v) queue' <- foldForM queue us $ ¥q (u, w) -> do writeArray dist u $! acc + w return $ q |> u aux queue' dist ༨ஊ ࢲ͜Ε͙Β͍ʹͳΔͱίϯςετ தʹॻ͖ͨ͘ͳ͍ͷͰϥΠϒϥϦԽ͠· ͕͢ɺ$ 1ZUIPOͰͬͯΔਓຖ ճ#'4ΛιϥͰهड़ͯͨ͠Γ͠·͢ -
ʮάϥϑͷྡϦετʯͷͨΊͷ࣮ʹͳͬͯ͠·͍ͬͯΔ let dist = bfs g [(1, 0)] • #'4άϥϑͷྡϦετͷͨΊ͚ͩͷ୳ࡧΞϧΰϦζϜͰͳ͍
• ྡϦετͷߏʹґଘ͍ͯ͠ΔՕॴΛύϥϝʔλԽ͠ɺநΛ্͛Α͏ -
நΛ্͛Δ uuu άϥϑͷભҠΛ֎෦͔ΒೖͰ͖ΔΑ͏ʹ͢Δ let dist = bfs (g !) (+)
(-1) (bounds g) [(1, 0)] • (g !) uuuʮW͔ΒḷΕΔ ʯͱ͍͏ࣸ૾ G – ʮ ͔Βɺ ̎ ͱ ɺͦΕͧΕॏΈ ͰભҠͰ͖ΔʯΛهड़͢Δؔ – f v = g ! v • ڑͷ݁߹ԋࢉ (+) -
#'4ͷ࣮Λม͑Δ͜ͱͳ͘ɺؔ GΛهड़͢Δ͚ͩͰ͕ղ͚Δ main = do [h, w] <- getInts grid
<- getCharGrid ((1, 1), (h, w)) let dist = bfs f (+) (-1) (bounds grid) [((1, 1), 0)] where f v = [ (u, 1) | d <- [(1, 0), (0, 1), (-1, 0), (0, -1)], let u = v + d, inRange (bounds grid) u, case (grid ! v, grid ! u) of ('s', 'n') -> True ('n', 'u') -> True ('u', 'k') -> True ('k', 'e') -> True ('e', 's') -> True _ -> False ] printYn $ dist ! (h, w) /= -1 ʮϚε WˠW͔Β౸ୡͰ͖ΔϚε VͷϦετʯ ͱ͍͏ࣸ૾ άϦουͷ্Լࠨӈʹ݅Λຬͨ͢ભҠઌ͕͋ΔͳΒ ͦΕΛྻڍ -
main = do [a, n] <- getInts let bounds =
(1, 10 ^ 6 + 1 :: Int) let dist = bfs f (+) (-1) bounds [(1, 0 :: Int)] where f x | x >= 10 && x `mod` 10 /= 0 = [(x', 1) | x' <- [rotate x, a * x], inRange bounds x'] | otherwise = [(a * x, 1) | inRange bounds (a * x)] rotate y = let ys = toDigits 10 y in fromDigits 10 (last ys : init ys) print $ dist ! n Γؔ GΛهड़͢Δ͜ͱͰ͕ղ͚Δ -
վΊͯ #'4ʹ͍ͯ͠Δؔ GͷҙຯΛߟ͑ͯΈΔ let dist = bfs f (+) (-1)
bounds [(1, 0 :: Int)] • f Λهड़͢Δ͚ͩͰ͕ղ͚Δ͕ɺf Կऀ? • (v -> [(v, e)]) • (ঢ়ଶ -> [(࣍ͷঢ়ଶ, ભҠίετ)]) ͱ͍͏ঢ়ଶભҠͷࣸ૾ ঢ়ଶ͔ΒભҠީิͷࣸ૾ ͱߟ͑Δ͜ͱ͕Ͱ͖Δ -
༨ஊ )BTLFMM Ҏ֎Ͱ͜Μͳ෩ʹ #'4ΛநԽͰ͖Δ • Θ͔Βͳ͍͚Ͳɺ؆୯Ͱͳͦ͞͏ • ભҠΛʮঢ়ଶભҠͷؔʯͱ͢Δ͜ͱͰ͖Δ • ঢ়ଶۭؒͷߏ
࣍ݩ ΛύϥϝʔλԽ͢Δ͜ͱͱɺύϑΥʔϚϯεΛཱ྆͢Δͷ͕͍͔͠ – )BTLFMMͷ "SSBZ࣍ݩΛύϥϝʔλԽͰ͖Δ -
for (int j = 0; j <= W; ++j) dp[0][j]
= 0; for (int i = 0; i < N; ++i) { for (int j = 0; j <= W; ++j) { if (j >= w[i]) dp[i+1][j] = max(dp[i][j-w[i]] + v[i], dp[i][j]); else dp[i+1][j] = dp[i][j]; } } cout << dp[N][W] << endl; ໋ྩతͳ࣮ uuu Մมͳೋ࣍ݩྻΛ༻ҙͯ͠ॻ͖͑Δ -
Ұͭલͷঢ়ଶΛ࣍ͷঢ়ଶʹભҠͤ͞ΔɻͦΕΛ࠶ؼతʹ uuu GPME͡ΌΜ main = do [n, wx] <- getInts
items <- replicateM n getTuple -- 初期状態の状態空間 let dp0 = accumArray @UArray max minBound (0, wx) [(0, 0 :: Int)] -- 状態空間を、再帰的に状態遷移させる let dp' = foldl' f dp0 items where f dp (wi, vi) = accum max dp [(w + wi, acc + vi) | (w, acc) <- assocs dp, inRange (bounds dp) (w + wi)] print $ maximum (elems dp) ՄมྻΛߋ৽͢Δͱ͍͏໋ ྩతͳ࣮Ͱͳ͘ɺෆมͳ ΛΈࠐΜͰ͍͘ɺͱ͍͏ )BTLFMMΒ͍࣮͠ʹ -
ʹݻ༗ͷ෦ΛύϥϝʔλԽ͠ɺGPMEʹΑΔ %1ܭࢉΛநԽ͢Δ -- 畳み込みDP -- ex) accumArrayDP @UArray f max
minBound (0, wx) [(0, 0)] wvs accumArrayDP :: ( IArray a e, Ix v, Eq e, Show e, Show v, Show (a v e), Foldable t ) => ((v, e) -> x -> [(v, e')]) -> -- 状態遷移関数 f v / x をみて v の次の遷移可能性を返す (e -> e' -> e) -> -- 緩和の二項演算 e -> -- 初期値 (0, minBound, maxBound, False など) (v, v) -> -- 状態空間の下界、上界 [(v, e')] -> -- 開始時点の状態 t x -> -- 入力 (時間遷移) a v e -- Array or UArray accumArrayDP f combine initial (l, u) v0s xs = let dp = accumArray combine initial (l, u) v0s in foldl' transition dp xs where transition dp x = accumArray combine initial (l, u) $ concatMap (filter (inRange (bounds dp) . fst) . (`f` x)) (assocs dp) -
φοϓβοΫ͜͏ղ͚Δ main = do [n, wx] <- getInts items <-
replicateM n getTuple let dp = accumArrayDP @UArray f max 0 (0, wx) [(0, 0)] items where f (w, acc) (wi, vi) = [(w, acc), (w + wi, acc + vi)] print $ maximum (elems dp) -
݁߹ͷํͱঢ়ଶભҠͷؔ ͋ͱॳظঢ়ଶ Λએݴ͢Εɺ%1͕ղ͚Δ main = do [n, wx] <- getInts
items <- replicateM n getTuple let dp = accumArrayDP @UArray f max 0 (0, wx) [(0, 0)] items where f (w, acc) (wi, vi) = [(w, acc), (w + wi, acc + vi)] print $ maximum (elems dp) -
%1ɺநԽͨ͠Β݁߹ͱࣸ૾͕ύϥϝʔλԽ͞Εͨ • ͷྲྀΕతʹೋ࣍ݩྻ ˠঢ়ଶۭؒͷΈࠐΈɺͱ͍͏ϞσϧͷసΛઌʹߟ͕͑ͨ • ࣮ࡍʹɺ%1ͷநԽΛࢼΈͨΒ GPMEͷ࣮ʹͳΓɺޙ͚ͰҙຯΛߟ͑ͨΒʮঢ়ଶۭؒ ͷΈࠐΈʯͱ͍͏Ϟσϧʹؾ͕͍ͭͨ • ʮ%1
NBQ SFEVDF GPME.BQ ͡Όͳ͍͔ ʜʯ – ࣸ૾ uuu ঢ়ଶͷભҠ – ݁߹ uuu ෳܦ࿏͔Βಉ͡ঢ়ଶʹྲྀೖͨ͠ͱ͖ɺΛҰͭʹू ˞ͨͩ͠ɺ͜ͷϞσϧͰղ͚ΔͷφοϓβοΫ%1ɻ֝ͼ%1͜ͷϞσϧͰղ͚ͳ͍ -
ΠϯλϑΣʔεΛோΊΔͱతߏݟ͑ͯདྷΔ uuu %1తߏΛ࣋ͭ let dp = accumArrayDP @UArray f (+)
0 (0, n) [(0, 0)] items f ((v, e) -> x -> [(v, e')]) ঢ়ଶ (v, e) ʹೖྗ x Λ࡞༻ͤ͞ෳͷભҠઌ (v, e') Λੜ͢Δ (࡞༻ తͳ๏) (+) (e -> e' -> e) ಉ͡ঢ়ଶʹෳભҠ͕ू·Δͱ͖ɺ·ͱΊΔ (Ճ๏) 0 e ॳظ (Ճ๏ͷ୯Ґݩ) • %1ɺ͋Δঢ়ଶ্ۭؒʹ͓͚ΔϞϊΠυʢࣸ૾ʣ࡞༻ͱɺ܈తͳूΛΈ߹Θͤͨܭࢉ • GPME.BQ.POPJEΛ͏͕ɺͦΕΛΑΓҰൠԽͯ͠4FNJSJOHʹ֦ுͨ͠ͷ͕%1Ͱ͋ΔͱΈͳͤ Δ -
நͷߏ ΠϯλϑΣʔε ͕ྑ͘ࣅ͍ͯΔ • #'4 %1ɺநతʹঢ়ଶۭؒʹΛΓɾूΊΔૢ࡞ͷ্ʹߏங͞ΕͨϞσϧ • #'4తߏ ·ͨͦͷ֦ு Λ࣋ͭ
·ͩͪΌΜͱߟ͑ΒΕ͍ͯ·ͤΜ let dp = accumArrayDP @UArray f (+) 0 (0, n) [(0, 0)] items let dist = bfs f (+) (-1) (0, n) [(1, 0)] -
f f f f f f (+), max, min, …
NBQ SFEVDF -
͠Ό͘ͱΓ๏ • (+) (-) 0 ··· ݁߹ɺٯݩɺ୯Ґݩ → ՄϞϊΠυ •
ʮՄϞϊΠυ্ͷ෦۠ؒͷྦྷੵʯʹରͯ͠ʮ݅ f Λຬͨ͢࠷େ۠ؒΛ୳ࡧ͢Δʯ – f ··· ϞϊΠυͷΈࠐΈʹରͯ͠ఆΛ͚ͨʮ͖݅ࣸ૾ʯ let secs = shakutori f (+) (-) 0 as -
͜Εۮવͳͷ͔ • )BTLFMMͰΞϧΰϦζϜΛநԽ͢Δͱɺ݁߹ ೋ߲ ԋࢉɺࣸ૾ ͋ͱॳظ ঢ়ଶ ͕ύϥϝʔλԽ͞ΕͯΠϯλϑΣʔεʹදΕΔ • NBQSFEVDF
• ͦͯ͠ΠϯλϑΣʔε͕ʮతߏΈʯΛଳͼΔ -
)BTLFMM࠶ؼతσʔλߏΛσʔλߏͷجຊͱ͍ͯ͠Δ data List a = Nil | Cons a (List
a) • )BTLFMMͷσʔλߏ uuu తσʔλܕʹΑΔ࠶ؼతσʔλߏ • ࠶ؼతσʔλߏʹదͨ͠࠷খͷૢ࡞͕ NBQͱ SFEVDF GPME – NBQ a -> b Λ֤ཁૉʹద༻͠ɺߏΛอͬͨ··ม ࠶ؼߏʹର͢Δؔద༻ͷ࠷খ୯Ґ – SFEVDF GPME ͦͷߏΛյ͠ͳ͕ΒҰͭͷʹΈࠐΉ ߏΛͨͨΉ࠶ؼతύλʔϯͷ࠷খ୯Ґ -
ʮࣸ૾ͱΈࠐΈʯͲ͔͜Βདྷͨͷ͔ • -JTQ ʙ ͕Ϧετʹର͢Δ NBQSFEVDFͰɺଟ͘ͷΛهड़Ͱ͖Δ͜ͱΛܦݧ తʹൃݟͨ͠ • ؔܕݴޠͷൃలʹΑΓɺNBQSFEVDF GPME
ϦετʹݶΒͳ͍࠶ؼతσʔλߏʹద ͨ͠ૢ࡞Ͱ͋ΔͱҰൠԽ͞Εͨ • )BTLFMM ʙ ͦΕΒΛཧ͚ͮͯ࠶ߏ͠ɺܕΫϥε֊ͱͱʹऔΓࠐΜͩ • 'VODUPS 'PMEBCMF "QQMJDBUJWF .POBE 5SBWFSTBCMF • NBQSFEVDF GPME )BTLFMMͷʮ࠶ؼʯͱʮߏԽʯΛ؏֩͘ɺݴޠઃܭͷத৺ʹ͋Δ -
)BTLFMMͷෆมͳσʔλߏ NBQSFEVDF GPME Ͱૢ࡞͢Δ • Ϧετɺ4FUɺ.BQɺ"SSBZ ͳͲͷෆมσʔλߏ͍ͣΕ 'PMEBCMFɻ·ͨ 'VODUPSͰ ͋ͬͨΓɺͦ͏Ͱͳͯ͘
NBQΛ͍࣋ͬͯΔ • ͦΕΒΛجૅʹΞϧΰϦζϜΛ࣮͠ɺ۩ମΛύϥϝʔλԽ͍ͯ͘͠ͱࣗવͱ NBQ GPME ͷҾ͕ύϥϝʔλͱͯ͠දΕΔ ͜Ε͕ΞϧΰϦζϜͷநʹG ͷΑ͏ͳ͕͍ؔͭදΕΔཧ༝ ӬଓσʔλϓϩάϥϛϯάΛࢤͨ͠߹ͷඞવ ˞ඞͣ͜͠ͷߏʹԊΘͳ͍ΞϧΰϦζϜσʔλߏɺͪΖΜ͋Γ·͢ -
ͳͥͦΕ͕ɺతߏͱ݁ͼͭ͘ͷ͔ • લड़ͷ௨Γ ࠶ؼతσʔλߏࣸ૾ͱ݁߹ʹࣗવʹؐݩͰ͖Δ • ঢ়ଶͷʮൖʯͱʮूʯతੑ࣭Λඞཁͱ͢Δ – ʮൖʯ֤ঢ়ଶΛ৽͍͠ঢ়ଶʹࣸ͢ ˠࣸ૾ –
ʮूʯෳͷ݁ՌΛҰͭʹ·ͱΊΔ ˠ݁߹ – ͜Ε͕݁߹తͰͳ͚Ε࠶ؼɾޮԽ͕͍͠ ˠతߏͷཁ ΞϧΰϦζϜΛநԽ͢Δͱࣸ૾ͱ݁߹͕ܭࢉͷຊ࣭తͳߏཁૉͱͯ͠ݱΕΔ ঢ়ଶۭؒΛू߹ͱΈͳ͢ͱɺతߏʢ'VODUPS .POPJE 4FNJSJOHʣʹରԠ͢Δ )BTLFMMͷܕͱߴ֊ؔɺͦͷߏΛࣗવʹΠϯλϑΣʔεͱͯ͠࿐ग़ͤ͞Δ நԽʮܭࢉͷʯΛՄࢹԽ͢ΔաఔͰ͋Δ -
)BTLFMMͷநͷɺڝٕϓϩάϥϛϯάʹ͓͚ΔҖྗ • ΞϧΰϦζϜͷநʹग़͖ͯͨࣸ૾݁߹ʮάϥϑͷભҠʯʮঢ়ଶભҠͷࣸ૾ʯͳͲҙຯ ͚ͮ͢Δ͜ͱ͕Ͱ͖Δ – ͨͩͷύϥϝʔλͰͳ͘ɺղऍΛՃ͑Δ͜ͱ͕Ͱ͖Δ – ͦͯͦ͠ΕΛతߏͷͰΈͯɺֶతੑ࣭Λҙࣝ͢Δ͜ͱͰ͖Δ • ڝٕϓϩάϥϛϯάͷ͕ɺͦͷҙຯʹैͬͯߟ͢Δ͜ͱͰղ͚Δ
– ෦Λղ͚ͩ͘Ͱɺશମ͕ղ͚Δ – ͜ͷࢥߟͷϑϨʔϜϫʔΫಛʹ %1άϥϑ୳ࡧͳͲʹ͓͍ͯڧྗͳثʹͳΔ -
໋ྩܕͰΞϧΰϦζϜΛॻ͘ͱ͖ uuuʮͲ͏ಈ͔͔͢ʯ • ؔ৺ʮखଓ͖ʯʮঢ়ଶͷมԽʯʹ͘ – ྻΛߋ৽͠ɺมΛมߋ͠ͳ͕ΒʮͲ͏ͬͯಈ͔͔͢ʯΛߟ͑Δ • Ұ࣌తͳதؒঢ়ଶ ໋ͳม Λͬͯʮ࠷ऴঢ়ଶʹͲ͏͍͔ͬͯ͘ʯʹूத͢Δ
• ΞϧΰϦζϜҰ࿈ͷ໋ྩͱͯ͠هड़͞ΕΔϨγϐ 🧠 ࢥߟʮ࣮ߦͷॱংʯʹԊͬͯਐΉɻಈ࡞ΛͳͧΔ͜ͱͰҙຯΛѲ͢Δɻ ϓϩηεࢤɺྲྀΕʹॏ͖Λஔ͘ࢥߟ -
for (int j = 0; j <= W; ++j) dp[0][j]
= 0; for (int i = 0; i < N; ++i) { for (int j = 0; j <= W; ++j) { if (j >= w[i]) dp[i+1][j] = max(dp[i][j-w[i]] + v[i], dp[i][j]); else dp[i+1][j] = dp[i][j]; } } cout << dp[N][W] << endl; -
ؔܕͰΞϧΰϦζϜΛॻ͘ͱ͖ uuuʮԿΛҙຯ͍ͯ͠Δ͔ʯ • ؔ৺ʮߏʯʮҙຯʯʹ͘ – ˠ͜ͷ NBQԿΛ͍ࣸͯ͠Δ ͜ͷ GPMEͲΜͳԋࢉΛू͍ͯ͠Δ •
ܭࢉෆมͳσʔλߏʹର͢Δࣸ૾ͱΈࠐΈͱͯ͠ߏ͞ΕΔ • ΞϧΰϦζϜࣸ૾ͱ݁߹ͷΈ͋Θͤͱͯ͠هड़͞ΕΔࣜ 🧠ࢥߟʮߏͱҙຯʯʹԊͬͯਐΉɻࣜͷߏΛோΊͯશମ૾Λଊ͑Δɻߏࢤɺؔʹॏ͖Λஔ͘ࢥߟɻ ܭࢉΛྲྀΕͱͯ͠͏ͷͰͳ͘ɺҙຯͷ͋Δߏ NBQ GPME ؔ߹ ͱͯ͠ଊ͑Δɻ Ұ࿈ͷૢ࡞ΛʮԿΛ͔ͨ͠ʯͰͳ͘ɺʮͲͷΑ͏ͳҙຯͷ͋Δࣸ૾݁߹Λఆ͍ٛͯ͠Δ͔ʯͱݟΔ -
let dp = accumArrayDP @UArray f max 0 (0, wx)
[(0, 0)] items where f (w, acc) (wi, vi) = [(w, acc), (w + wi, acc + vi)] print $ maximum (elems dp) -
நԽָ͕͍͠ͷΘ͔͚ͬͨͲɺڝϓϩΛ )BTLFMMͰΔϝϦοτ • ͋Γ·͢ΑͰͦΜͳ͜ͱͲ͏Ͱ͍͍͡Όͳ͍Ͱ͔͢ɻϩϚϯͰ͢ – ϝϦοτϝϦοτ͏ΔͤʔΜͩΑ – )BTLFMMͰղ͚ͳ͍ʹग़ձͬͨ͜ͱͳ͍ – ʮ)BTLFMMʹΑΔந͕ิॿྠʹͳΔʯ͜Ε͚ͩͰेͳϝϦοτ
• ΑΓ۩ମతͳϝϦοτྫ͑uuu – )BTLFMMͷ࠶ؼσʔλܕ Ӭଓσʔλߏ ˠ ӬଓσʔλߏΛલఏʹͨ͠ͷղ – ʮӬଓσʔλϓϩάϥϛϯάͱڝٕϓϩάϥϛϯά ʙ )BTLFMMͰ͕ΜΔڝϓϩʯ • IUUQT[FOOEFWOBPZB@JUPBSUJDMFTBCEDBBBC -
)BTLFMM͛͢ʔͳͱࢥ͏͜ͱ • ࠓͯ͠ΔΑ͏ͳ͜ͱΛ͔ͬͯͯ )BTLFMMΛͬͯདྷͨΘ͚Ͱͳ͍ • )BTLFMMΛ͍ͬͯͨΒࣗવͱࠓͨ͠Α͏ͳநԽͷ࣮ʹͳͬͨ • ͦͷநԽͷҙຯΛߟ͍͑ͯΔ͏ͪʹࠓͨ͠Α͏ͳߟʹࢸͬͨ • )BTLFMMΛͬͯΔͱ͜͏͍͏ܦݧΛԿ͢Δ
– ·ΔͰϓϩάϥϛϯάݴޠͱ͍͏ಓ۩͕ɺΑΓྑ͍நͱීวͷಓےΛࢦࣔͯ͘͠͠Ε͍ͯΔΑ͏ͳײ͡ -
ͨ͜͠ͱ • )BTLFMM ͰڝٕϓϩάϥϛϯάʹࢀՃ͍ͯ͠ΔɻΞϧΰϦζϜΛநԽ͢Δͱɺͦͷ࣮͕ ࣅͨΑ͏ͳΠϯλϑΣʔεʹͳΔ͜ͱΛܦݧͨ͠ – ߴ֊ؔͱͯࣸ͠૾ Gͱ݁߹ͷೋ߲ԋࢉ͕ύϥϝʔλͱͯ͠Α͘දΕΔ • ͦΕۮવͳͷ͔ɺ͍ɺۮવͰͳ͍
– )BTLFMMͷࠜఈʹ͋Δ࠶ؼσʔλߏɺͦΕʹ࠷దͳૢ࡞Ͱ͋Δࣸ૾ͱΈࠐΈ NBQSFEVDF • ࣸ૾ͱΈࠐΈʹΑΔؔͷΠϯλϑΣʔε͔ΒΞϧΰϦζϜͷతߏ͕ݟ͑Δ • ؔܕϓϩάϥϛϯάɺ)BTLFMMΞϧΰϦζϜΛΑΓநߴ͘ଊ͑ΔࢥߟΛิॿͯ͘͠ ΕΔ -
NJTD • ෆมͳσʔλߏͱ NBQSFEVDFͰશ෦͍͚Δͷ – ͍͍͑ɻύϑΥʔϚϯεͷ؍͔Β .VUBCMF"SSBZ͕ඞཁͳ໘͋Γ·͢ • 6OJPO'JOEɺηάϝϯτɺԆධՁηάϝϯτͳͲͷ࣮ –
.VUBCMF"SSBZͷૢ࡞Ϟφυͷݟ͔ΒݟΕ NBQSFEVDFతͳͷͱͯ͠ଊ͑Δ͜ͱͰ ͖Δ͕ɺͦΕΛѻ͏ਓؒͷϝϯλϧϞσϧͱ໋ͯ͠ྩܕతͳૢ࡞ – .VUBCMF"SSBZඇ࠶ؼతͳݻఆαΠζͷઢܗߏͰ͋ΓɺతσʔλܕͰએݴ͞ΕΔ࠶ؼత σʔλߏͱҟͳΔͷ • ೖग़ྗཚಉ༷ͷɺ֎ք 3FBM8PSME ͷӨڹԼʹ͋Δ෭࡞༻తͳଘࡏ ֎෦ࢿݯ ϝϞϦ ͱͷڮ͠ஔ • .POPJEͱ͔ 4FNJHSPVQͱ͔ͷܕ࣮ͬͯ͠ͳ͍ͷ – ࢲͬͯ·ͤΜ͕ɺͬͯ៉ྷͳநΛ࣮͍ͯ͠Δ "U$PEFSͷઌഐํ͍·͢ – ࢲ׳Εͱهड़ͷָ͞Λ༏ઌ͍ͯ͠·͢