遍历游戏状态空间:更多的搜索导致糟糕的结果

我在codereview上发布了这个问题,因为我发现那里没有回应,所以我在这里重复发布这个问题。

这个问题可以在hackerrank ai上找到。我不是在寻求解决方案,而是在试图找出我的策略或代码中有什么问题。

我试图解决一个我认为是2-D网格上的TSP的问题。因此,我试图获得我能得到的最佳结果。然而,前瞻一步比前瞻两步产生更好的结果。

问题是我必须在2-D网格上以最少的移动次数清理脏块,移动可以是UP, DOWN, LEFT, RIGHT, CLEAN

另一个重要的事情是我做出一个移动后,过程会以网格的新状态和我的新位置重新开始,所以我必须再次运行算法。这也意味着我必须避免陷入循环,这在单一进程的情况下很容易避免,但在多实例进程的情况下需要算法来保证。

简而言之,我在我的进程中只需要做出next_move

所以基本策略是找到离我当前位置最近的脏单元格。

为了前瞻一步,我会这样做:对于每个脏单元格,找到离所选脏单元格最近的脏单元格。对于两步,对于每个脏单元格,进行一步查找并找到最佳移动。对于多步也是如此操作。

然而,当我只进行一步查找时,我得到的分数更高,而进行两步查找时分数较低。分数的计算方式是(200 - steps_taken)。所以,我认为我的代码/策略中有些地方出了问题。

输入格式 :

b代表网格中的机器人。-是干净的单元格。d是脏单元格。

第一行是机器人位置的整数对。这使得网格中的b变得多余。如果机器人当前站在一个脏单元格上,那么网格中那个单元格上会有一个d

第二行是网格的维度。

第三个输入是网格的行形式。请查看下面的示例输入。

我的Haskell代码是 :

module Main whereimport Data.List import Data.Function (on)import Data.Ord-- slits up a string -- ** only used in IO. split sep = takeWhile (not . null) . unfoldr (Just . span (/= sep) . dropWhile (== sep))-- ** only used in IOgetList :: Int -> IO [String]getList n = if n==0 then return [] else do i <- getLine; is <- getList(n-1); return (i:is)-- find positions of all dirty cells in the boardgetAllDirtyCells :: (Int, Int) -> [String] -> [(Int, Int)]getAllDirtyCells (h, w) board = [(x, y) | x <- [0..(h-1)], y <- [0..(w - 1)]                               , ((board !! x) !! y) == 'd']-- finally get the direction to print ;-- first argument is my-position and second arg is next-position.getDir :: (Int, Int) -> (Int, Int) -> StringgetDir (x, y) (a, b) | a == x && y == b = "CLEAN"                     | a < x = "UP"                     | x == a && y < b = "RIGHT"                     | x == a = "LEFT"                     | otherwise = "DOWN"-- only used in IO for converting strin gto coordinate.getPos :: String -> (Int, Int)getPos pos = let a = map (\x -> read x :: Int) (words pos)             in ((a !! 0) , (a !! 1))-- manhattan Distance :  sum of difference of x and y coordinatesmanhattanDis :: (Int, Int) -> (Int, Int) -> IntmanhattanDis (a, b) (x, y) = (abs (a - x) + (abs (b - y)))-- sort the positions from (botX, botY) position on manhattan-distance.-- does not returns the cost.getSortedPos :: (Int, Int) -> [(Int, Int)] -> [(Int, Int)]getSortedPos (botX, botY) points = map (\x -> (snd x)) $                                    sortBy (comparing fst)  -- compare on the basis of cost.                                              [(cost, (a, b)) |                                                      (a, b) <- points,                                                      cost <- [manhattanDis (a,b) (botX, botY)]]-- exclude the point `v` from the list `p`excludePoint :: (Ord a) => [a] -> a -> [a]excludePoint [] _ = []excludePoint p v = [x | x <- p , x /= v]-- playGame uses the nearest-node-policy. -- we start playing game when we are not going more deep. -- more about that in findBestMove-- game is to reduce the nodes to one node with the total cost ;-- reduction : take the next shortest node from the current-node.playGame :: (Int, Int) -> [(Int, Int)] -> [(Int, Int)]playGame pos [] = [pos]playGame startPos points = let nextPos = (head (getSortedPos startPos points))                           in (nextPos : playGame nextPos (excludePoint points nextPos))-- sum up cost of all the points as they occur.findCost :: [(Int, Int)] -> IntfindCost seq = sum $ map (\x -> (manhattanDis (fst x) (snd x))) $ zip seq (tail seq)-- find the position which gives the smallest overall cost.smallestCostMove :: [(Int, (Int, Int))] -> (Int, (Int, Int))smallestCostMove [] = (0, (100, 100))smallestCostMove [x] = xsmallestCostMove (x:y:xs) | (fst x) <= (fst y) = smallestCostMove (x : xs)                          | otherwise = smallestCostMove (y : xs)                      -- This is actual move-finder. It does the lookups upto `level` deep.-- from startpoint, take each point and think it as starting pos and play the game with it.-- this helps us in looking up one step.-- when level is 0, just use basic `playGame` strategy. findBestMove :: (Int, Int) -> [(Int, Int)] -> Int -> (Int, (Int, Int))findBestMove startPos  points level                                     -- returns the move that takes the smallest cost i.e. total distances.                                    | level == 0 = smallestCostMove $                                                      -- return pair of (cost-with-node-x-playGame, x)                                                     map (\x -> (findCost (startPos : (x : (playGame x (excludePoint points x)))),                                                                 x))                                                          points                                    | otherwise  = smallestCostMove $                                                      map (\x ->                                                            -- return pair of (cost-with-node-x, x)                                                            ( (findCost (startPos : [x])) +                                                               -- findBestMove returns the pair of (cost, next-move-from-x)                                                              (fst (findBestMove x (excludePoint points x) (level - 1))),                                                             x))                                                          points-- next_move is our entry point. go only 2 level deep for now, as it can be time-expensive.next_move :: (Int, Int) -> (Int, Int) -> [String] ->  Stringnext_move pos dim board = let boardPoints = (getAllDirtyCells dim board)                              numPoints = (length boardPoints)                              -- ** Important : This is my question :                              -- change the below `deep` to 1 for better results.                               deep = if (numPoints > 3)                                      then 2                                      else if (numPoints == 1)                                           then 1                                           else (numPoints - 1)                                                          in if pos `elem` boardPoints                              then getDir pos pos                             else getDir pos $ snd $ findBestMove pos boardPoints deepmain :: IO()main = do    -- Take input   b <- getLine   i <- getLine   -- bot contains (Int, Int) : my-coordinates. like (0,0)   let botPos = (read $ head s::Int,read $ head $ tail s::Int) where s = split (' ') b   -- dimOfBoard contains dimension of board like (5,5)   let dimOfBoard = (read $ head s::Int, read $ head $ tail s::Int) where s = split (' ') i   board <- getList (fst dimOfBoard)   putStrLn $ next_move botPos dimOfBoard board

我通过变量deep来控制我可以深入的程度。

示例板面是:

0 05 5b---d-d--d--dd---d------d

可以有三个答案:

输出

RIGHT or DOWN or LEFT

重要:再次强调,新进程将使用新的板面我的机器人的新位置被调用,直到我清理完所有脏单元格。

我做错了什么?


回答:

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注