HaskellでAtCoderやるぜ2

2 min read読了の目安(約2200字

Haskellで蟻本やるぜ5(DP)で、ナップサック問題を解いたので、早速AtCoderに登録してみるぜ。

これだ。

ちなみに、AtCoderでHaskellを使う場合には、ByteString型を使う方がよいらしい。
詳しい説明は、HaskellでAtCoderの問題を解く(入力の高速化編)を参照だぜ。

ByteString型を使って標準入力からデータ取得

import qualified Data.ByteString.Char8 as BS
import qualified Data.List as DL
import qualified Data.Char as DC
import qualified Control.Monad as CM

getintlist = DL.unfoldr (BS.readInt .  BS.dropWhile DC.isSpace) <$> BS.getLine

main :: IO ()
main = do
    [n,maxW] <- getintlist
    items <- CM.replicateM n $ do
      [w,v] <- getintlist
      return (w,v)
    print $ q1' n maxW items

大量データとの戦い

前回のときには、テストデータが少ないせいか、DPよりも単にHaskellで書いた方が速度がでた。
果たして大量データの場合はどうなるのか!!!???

となり、DP版が勝った!
メモしなくてもよいんだ。。使用メモリ量も大差ないし。。

DP版のコード

一応、優勝したコードを記念コピペ。

-- https://lvs7k.github.io/posts/2018/11/pccb-easy-3/
{-# LANGUAGE BangPatterns, FlexibleContexts #-}

import Control.Monad
import Control.Monad.ST
import Data.Array.ST
import Data.Array

import qualified Data.ByteString.Char8 as BS
import qualified Data.List as DL
import qualified Data.Char as DC
import qualified Control.Monad as CM

q1' :: Int -> Int -> [(Int, Int)] -> Int
q1' n m wvs = runST $ do
    dp <- newArray ((0, 0), (n, m)) 0 :: ST s (STUArray s (Int, Int) Int)
    forM_ [1 .. n] $ \i -> do
        let (w, v) = wva ! i
        forM_ [0 .. m] $ \j -> do
            x1 <- readArray dp (i - 1, j)
            if j < w
              then writeArray dp (i, j) x1
            else do
              x2 <- readArray dp (i - 1, j - w)
              writeArray dp (i, j) (max x1 (x2 + v))
    readArray dp (n, m)
  where
    wva = listArray (1, n) wvs

getintlist = DL.unfoldr (BS.readInt .  BS.dropWhile DC.isSpace) <$> BS.getLine

main :: IO ()
main = do
    [n,maxW] <- getintlist
    items <- CM.replicateM n $ do
      [w,v] <- getintlist
      return (w,v)
    print $ q1' n maxW items