Algorithm 在Haskell中求解代码chef(chef and Way)上的CHRL4

Algorithm 在Haskell中求解代码chef(chef and Way)上的CHRL4,algorithm,haskell,functional-programming,Algorithm,Haskell,Functional Programming,我试图在Haskell中解决这个问题,但codechef编译器一直说这是错误的答案。问题如下: import qualified Data.ByteString.Char8 as B import Data.Maybe (fromJust) findMinIndex x index minIndex n | index == n = minIndex | (x!!index) < (x!!minIndex) = findMinIndex x (index+1)

我试图在Haskell中解决这个问题,但codechef编译器一直说这是错误的答案。问题如下:

import qualified Data.ByteString.Char8 as B
import Data.Maybe (fromJust)


findMinIndex x index minIndex n
      | index == n = minIndex
      | (x!!index) < (x!!minIndex) = findMinIndex x (index+1) index n
      | otherwise = findMinIndex x (index+1) minIndex n


minCost []     _ = 1
minCost (x:xs) k = let indexList = take k xs
                       minIndex = findMinIndex indexList 0 0 (length indexList)
                   in x * minCost(drop minIndex xs) k

main :: IO()
main = do
       t <- B.getContents
       let inputs = B.lines t
       let firstLine = inputs !! 0
       let secondLine = inputs !! 1
       let [n,k] = map (fst . fromJust . B.readInt) $ B.split ' ' firstLine
       let specialNums = reverse $ map (fst . fromJust . B.readInteger) $ B.split ' ' secondLine
       putStrLn $ show ((minCost specialNums k) `mod` 1000000007)

在拜访了一位儿时的朋友后,这位厨师想回家。朋友住在第一条街,厨师自己住在第N条街(也是最后一条街)。他们的城市有点特别:当且仅当1您的算法不总是为所有输入提供最小乘积时,您可以从X街移动到Y街,例如:

5 2
3 2 3 2 3
这本书通篇解释了这个问题,你真的应该再读一遍

这个问题基本上是一个最短路径问题,街道是顶点,从街道到街道的可能移动是图的边,边的权重仅由尾部的特殊值决定。虽然总移动成本被定义为产品,但不是所有成本的总和,但问题可以通过取所有特殊值的对数来标准化,因为

a*b=exp(log(a)+log(b))

给定对数是单调递增函数,最小乘积就是对数的最小和

在社论中,编辑选择了Dijkstra的算法,但在进行了日志转换之后,这将是一个标准的最短路径问题,可以用您喜欢的任何最短路径算法来解决

在Haskell中有许多Dijkstra算法的实现,我在Hackage中发现了两个,一个。解析和图形初始化代码非常简单

import           Control.Monad      (foldM)
import           Control.Monad.ST
import           Data.Array
import           Data.Array.MArray
import           Data.Array.ST
import           Data.Function      (on)
import           Data.IntMap.Strict as M
import           Data.List          (groupBy)
import           Data.Set           as S

-- Code from http://rosettacode.org/wiki/Dijkstra's_algorithm#Haskell
dijkstra :: (Ix v, Num w, Ord w, Bounded w) => v -> v -> Array v [(v,w)] -> (Array v w, Array v v)
dijkstra src invalid_index adj_list = runST $ do
  min_distance <- newSTArray b maxBound
  writeArray min_distance src 0
  previous <- newSTArray b invalid_index
  let aux vertex_queue =
        case S.minView vertex_queue of
          Nothing -> return ()
          Just ((dist, u), vertex_queue') ->
            let edges = adj_list Data.Array.! u
                f vertex_queue (v, weight) = do
                  let dist_thru_u = dist + weight
                  old_dist <- readArray min_distance v
                  if dist_thru_u >= old_dist then
                    return vertex_queue
                  else do
                    let vertex_queue' = S.delete (old_dist, v) vertex_queue
                    writeArray min_distance v dist_thru_u
                    writeArray previous v u
                    return $ S.insert (dist_thru_u, v) vertex_queue'
            in
            foldM f vertex_queue' edges >>= aux
  aux (S.singleton (0, src))
  m <- freeze min_distance
  p <- freeze previous
  return (m, p)
  where b = bounds adj_list
        newSTArray :: Ix i => (i,i) -> e -> ST s (STArray s i e)
        newSTArray = newArray

shortest_path_to :: (Ix v) => v -> v -> Array v v -> [v]
shortest_path_to target invalid_index previous =
  aux target [] where
    aux vertex acc | vertex == invalid_index = acc
                   | otherwise = aux (previous Data.Array.! vertex) (vertex : acc)


-- Code I wrote
instance Bounded Double where
    minBound = -1e100
    maxBound = 1e100

constructInput :: Int -> Int -> M.IntMap Integer -> Array Int [(Int, Double)]
constructInput n k specMap =
    let
        specMap' = fmap (log . fromIntegral) specMap
        edges = [(src, [(dest, specMap' M.! dest) | dest <- [src+1..src+k], dest <= n]) | src <- [1..n]]
    in
        array (1, n) edges

main :: IO ()
main = do
    rawInput <- getContents
    let
        [l, l'] = lines rawInput
        [n,k] = fmap read . words $ l
        specs = fmap read . words $ l'
        specMap = M.fromList $ [1..n] `zip` specs
        adj_list = constructInput n k specMap
        (_, previous) = dijkstra 1 0 adj_list
        path = shortest_path_to n 0 previous
        weight = (product $ fmap (specMap M.!) path) `mod` 1000000007
    print weight
import Control.Monad(foldM)
进口管制站
导入数据。数组
导入Data.Array.MArray
导入Data.Array.ST
导入数据。函数(打开)
将Data.IntMap.Strict导入为M
导入数据列表(groupBy)
导入数据。设置为S
--代码来自http://rosettacode.org/wiki/Dijkstra's#u算法#Haskell
dijkstra::(Ix v,Num w,Ord w,Bounded w)=>v->v->Array v[(v,w)]->(Array v w,Array v v)
dijkstra src无效索引调整列表=runST$do
最小距离>=aux
辅助(S.singleton(0,src))
m e->ST s(斯塔雷s i e)
newSTArray=newArray
最短路径到::(Ix v)=>v->v->Array v->[v]
到目标的最短路径无效索引先前=
辅助目标[]在哪里
辅助顶点acc |顶点==无效_索引=acc
|否则=辅助(上一个数据数组!顶点)(顶点:acc)
--我写的代码
实例有界双精度
minBound=-1e100
maxBound=1e100
constructInput::Int->Int->M.IntMap Integer->Array Int[(Int,Double)]
构造输入n k specMap=
让
specMap'=fmap(log.fromIntegral)specMap

edges=[(src,[(dest,specMap'M.!dest)| dest我不知道您需要多少提示,但您的算法并不总是找到最佳(=最小乘积)路径。谢谢。几天后我意识到了这一点并更正了代码。现在它可以工作了。再次感谢您