Haskell求讨论
查看原帖
Haskell求讨论
625398
_OTZ_楼主2024/10/20 15:42

业余Haskell爱好者,欢迎大家前来讨论,有啥说啥

思路

  1. 预处理成区间 [开始点,终点,区间油价]
  2. 合并区间, 尽量让油耗小的区间长
  3. 最后分别计算区间油耗相加

变量命名的含义(瞎写的,不解释看不懂)

  • d0 区间开始点
  • d1 区间结束点
  • pd0 上一区间开始点
  • 一般前面的p就是pre,p是价格
  • ps 区间的加油点

函数含义

  • clac 将一开始预处理的区间记录状态,读取环境
  • myMerge 合并区间

数据结构含义

StateT [((Double 开始点, Double 结束点, Double 单价), Double 加油点)] (Reader Double 最大油耗) ()


module Main where

import Control.Monad
import Control.Monad.Reader
import Control.Monad.State
import Data.List
import Text.Printf

main :: IO ()
main = do
  [d1, c, d2, p, n] <- fmap read . words <$> getLine
  disToPrice <- fmap (([0, p] :) . sort . ([d1, 0] :)) $ replicateM (truncate n) $ fmap read . words <$> getLine
  let preprocessing = fmap (\([d0, p0], [d1, _]) -> (d0 / d2, d1 / d2, p0)) $ zip disToPrice $ tail disToPrice
  putStrLn $
    if (> 0) . length . filter (\(d0, d1', _) -> (d1' - d0) > c) $ preprocessing
      then "No Solution"
      else printf "%.2f\n" . sum . fmap (\((d0, d1, p), _) -> (d1 - d0) * p) . flip runReader c . flip execStateT mempty $ foldl1' (>>) $ calc <$> preprocessing

calc :: (Double, Double, Double) -> StateT [((Double, Double, Double), Double)] (Reader Double) ()
calc disAndPrice@(d0, _, p) = do
  preDisAndPrices <- get
  if null preDisAndPrices
    then put [(disAndPrice, 0)]
    else do
      let pre@((_, _, pp), _) = head preDisAndPrices
      if p <= pp
        then do
          modify (((disAndPrice), d0) :)
        else myMerge disAndPrice

myMerge :: (Double, Double, Double) -> StateT [((Double, Double, Double), Double)] (Reader Double) ()
myMerge curDAP@(d0, d1, p) = do
  maxCapacity <- ask
  preDisAndPrices <- get
  let (preDAP@((pd0, pd1, pp), ps) : daps) = preDisAndPrices
  if d1 - ps <= maxCapacity
    then put $ ((pd0, d1, pp), ps) : daps
    else put $ ((pd0 + maxCapacity, d1, p), d0) : ((pd0, pd0 + maxCapacity, pp), ps) : daps
2024/10/20 15:42
加载中...