Algorithm 以最少的移动同时解决所有4x4迷宫
我遇到了一个非常有趣的问题,我们有一个4x4迷宫,里面有一个机器人试图到达目标。问题是,您必须找到一系列预定义的命令,这些命令将始终导致机器人达到目标 假设我们有一个这样的迷宫:Algorithm 以最少的移动同时解决所有4x4迷宫,algorithm,path-finding,maze,Algorithm,Path Finding,Maze,我遇到了一个非常有趣的问题,我们有一个4x4迷宫,里面有一个机器人试图到达目标。问题是,您必须找到一系列预定义的命令,这些命令将始终导致机器人达到目标 假设我们有一个这样的迷宫: x . . . . # # . . # # . . . . g 例如,可以使用命令序列DDDRRR或RRRDDD来解决这个特定的迷宫,其中R=right,L=left,U=up,D=down(duh) 然而,这两个序列都不能解决这个迷宫: x . # . . . . . # . . . . . . g 0 1 0
x . . .
. # # .
. # # .
. . . g
例如,可以使用命令序列DDDRRR
或RRRDDD
来解决这个特定的迷宫,其中R=right,L=left,U=up,D=down(duh)
然而,这两个序列都不能解决这个迷宫:
x . # .
. . . .
# . . .
. . . g
0 1 0 0
0 1 0 0
0 0 0 0
0 1 0 0
机器人总是从左上角开始,目标总是在右下角,迷宫总是一个2D 4x4矩阵 我已经实现了一个算法,使我获得了78条命令的成功序列。我确信至少存在29条命令的解决方案(这是由其他人完成的) 这个问题实际上已经存在了几年,因此我丢失了当时使用的算法,但是基本思想是搜索我生成的所有迷宫,并始终选择导致解决最多迷宫的路线。这实际上给了我一个长度略大于78的序列;我用手减少了一些多余的命令 是的,暴力强迫将像往常一样需要几年的时间 如果我能记起的话,可能的迷宫不到4000个(可能的迷宫是在左上角和右下角之间存在一条路径) 哦在执行命令期间,机器人只需访问目标至少一次就足够了。也就是说,它不必在最后一次命令后坐在球门上 我有没有引起任何人的兴趣?我应该如何处理这个问题以获得更有效的答案?感谢您的考虑:)
有趣的事: 这是一个(非常)匆忙拼凑起来的Java。它应该编译并运行:) 该程序可以同时播放约4000个迷宫。程序接受上、左、下和右的输入(w、a、s、d),然后模拟移动,显示一些统计信息。如果您尝试,您可以在屏幕上看到每个迷宫中每个位置的障碍物总数,以及每个迷宫当前位置的总数。很难解释:)如果你有问题问我 再次。。。不要介意那些可怕的代码。它是在20分钟内写成的
进展 我间接地从中得到了这个想法,并在聊天中对其进行了进一步的建模。这个想法是找到一个序列来解决迷宫的右侧。也就是说,解决至少一半迷宫的解决方案,当镜像并从一开始再次运行时解决剩余的迷宫 说明: 首先找到一个序列,其第一个命令是正确的,该序列可以解决以下问题,例如:
x . # .
. . . .
# . . .
. . . g
0 1 0 0
0 1 0 0
0 0 0 0
0 1 0 0
一个这样的序列是RDDRRRD
。此序列的镜像对应项是这样的:
R -> D
D -> R
L -> U
U -> L
这意味着RDDRRRD
->DRRDDDR
现在,这个镜像序列解决了迷宫吗?不,它卡住了。因此,即使对于这个迷宫,它也不是一个有效的序列。我们必须找到这样一个序列,它解决了至少一半的迷宫,当从一开始再次运行时,它的镜像对应解决了其余的迷宫
在简单地强制所有可能的R、D和L排列之后,我得到了一些可能的序列
一个这样的序列是rrdrdrldrdr
现在下一个问题是,在运行这个序列之后,剩余的迷宫处于随机混乱中。我们需要得到最短的(最佳的)可能的序列,这将使所有剩余的迷宫回到起始位置(0,0)。这部分我只是手工做的(现在)。我的答案绝对不是最优的,但它让所有的迷宫回到了起点
此序列是ldlulull
在此之后,我们只需运行镜像序列,ddrdrdrdrd
,就解决了所有的难题
这一特定序列的整体:
rrdrdrldrdrludlululululullddrdrdrdrdrdrd
-41移动
虽然这是一个有希望的里程碑,但距离最佳解决方案还有12步之遥。欢迎有任何见解!同时,感谢迄今为止帮助我的所有人:)
序列缩小
到目前为止,我还无法通过编程获得比58步长序列更好的答案。然而,使用上面描述的方法,只需手工研磨字符,我就能够将序列缩短到只有33个字符长。这一顺序如下:
RRDRRDRLDRDLULLLLDDRDDRRRDDR
-33步
虽然序列现在非常接近29目标,但我仍然在寻找一种以编程方式获得的相同质量的解决方案。在从序列中删除字符时,我没有使用任何逻辑-我只是删除了一个字符,然后检查它是否解决了所有迷宫,冲洗并重复。听起来你可以在这里使用*搜索,将所有迷宫中的最大启发式作为启发式。这保守地近似于解决方案的距离,可能会给出合理的第一种方法 由于所有迷宫都很小,因此可以通过从每个迷宫的末端反向运行BFS来为每个迷宫构建一个完美的启发式,以预计算从每个点到每个迷宫目标的距离。如果您将其缓存在查找表中,您可能会有一个每个迷宫的启发式算法,它可以完美地告诉您剩余的最小移动次数 我还没有真正尝试过,所以这仍然有待实验验证,但我认为这将是解决方案的一个很好的起点 编辑我刚刚读到一张便条,上面说每个机器人必须至少访问目标一次,而不一定要在目标上结束。在这种情况下,将启发式修改为距离任何尚未移动的机器人的最大距离
x # * * . x * *
* * * * * * * *
* * * * * * * *
* * * g * * * g
. # * * . x * * . . * *
x * * * * # * * * x * *
* * * * * * * * * * * *
* * * g * * * g * * * g
x # * *
. # * *
. # # *
. . . g
xx#x
x#xx
xxxx
xx#x
x#xx
#xxx
xxxx
xxxx
xx#x
x#xx
xxxx
xxxx
xxx#
xx#x
xxxx
xxxx
xxxx xxxx xxxx xxxx xxxx xxxx
xxx# x#xx xx#x xxxx xxxx xxxx
xxxx #xxx x#xx xxx# x#xx xx#x
xxxx xxxx xxxx xxxx #xxx x#xx
xxxx
xxx#
xx#x
xxxx
xxxx xxxx
xxxx xxxx
xxx# xxxx
xx#x xxx#
RRDRRDRLDRDLDLULLLDDRDDRDRURRDRD (32 characters)
RRDRRDRLDRDLDLULLLDDRDDRDURRDRRD (32 characters)
RRDRRDRLDRDLDLULLLDDRDDDURDRRDR (31 characters)
//// 33 char solution
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRRDDR", 33); // 33 chars, 00:00:00.0032911 Finished, 1 solution, best 33, visitedList length 0
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRRDD", 33); // 32 chars, 00:00:00.0308543 Finished, 1 solution, best 33, visitedList length 3
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRRD", 33); // 31 chars, 00:00:00.0871429 Finished, 2 solutions, best 33, visitedList length 14
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRR", 33); // 30 chars, 00:00:00.2536057 Finished, 2 solutions, best 33, visitedList length 49
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURR", 33); // 29 chars, 00:00:01.0540762 Finished, 8 solutions, best 32, visitedList length 205
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRUR", 33); // 28 chars, 00:00:03.8993877 Finished, 7 solutions, best 32, visitedList length 771
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRU", 33); // 27 chars, 00:00:10.4225150 Finished, 7 solutions, best 32, visitedList length 2069
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDR", 33); // 26 chars, 00:00:24.2552908 Finished, 7 solutions, best 32 visitedList length 4484
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRD", 33); // 25 chars, 00:01:44.3295165 Finished, 14 solutions, best 32, visitedList length 16600
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDR", 33); // 24 chars, 00:16:18.6666045 Finished, 14 solutions, best 32, visitedList length 77106
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURR", 32); // 29 chars, 00:00:00.3134699 Finished, 1 solution, best 32, visitedList length 66
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRUR", 32); // 28 chars, 00:00:01.1053798 Finished, 1 solution, best 32, visitedList length 238
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRU", 32); // 27 chars, 00:00:03.5172143 Finished, 1 solution, best 32, visitedList length 730
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDR", 32); // 26 chars, 00:00:07.1336796 Finished, 1 solution, best 32, visitedList length 1413
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRD", 32); // 25 chars, 00:00:26.4906874 Finished, 2 solutions, best 32, visitedList length 5084
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDR", 32); // 24 chars, 00:02:52.8134463 Finished, 2 solutions, best 32, visitedList length 24623
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDD", 32); // 23 chars, cancelled after 6 seconds, finds RRDRRDRLDRDLDLULLLDDRDDDURDRRDR (31 chars)
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDD", 31); // 23 chars, 00:01:58.4861802 Finished, 1 solution, best 31, visitedList length 18835
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRD", 30); // 22 chars, 00:00:34.6602434 Finished, 0 solution, best distance 44, visitedList length 21084
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDR", 30); // 21 chars, 00:04:32.2439241 Finished, 0 solution, best distance 44, visitedList length 78500
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDD", 30); // 20 chars, cancelled after 10 minutes, found no solution, best distance 44
//var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLD", 30); // 19 chars, cancelled after 10 minutes, found no solution, best distance 44
//var aStarSearch = new AStarSearch("R", 29); // Complete search, would take waaay too long and consume much memory
RRDRRDRDLDLDULLDLDRDDURDRRDRR
import Data.List(tails,nub)
import Data.Bits
import Numeric(showHex)
import System.Environment(getArgs)
data Lit = Lit Bool [Char]
type Wall = Int -- [Bool]
lit s = Lit True s
litS s = lit (s "")
inv (Lit b s) = Lit (not b) s
instance (Show Lit) where
showsPrec _ (Lit b s) = showString (if b then "" else "~") . showString s
showList = showString . unwords . (map show)
showDir d = showChar ("NESW"!!d)
dir n d = litS $ showChar 'D' . shows n . showDir d
showStuff n s p = showHex n . showChar (['A'..]!!p) . shows s
pos n s p = litS $ showChar 'P' . showStuff n s p
posh n s p h = litS $ showDir h . showStuff n s p
opdir :: Int -> Int
opdir d = (d+2) `mod` 4
(<-&) :: Lit -> [Lit] -> [[Lit]]
l <-& ls = lt : lf where
lt = l : map inv ls -- l or ~l1 or ~l2 ...
lf = [ [ inv l, li ] | li <- ls ] -- ~l or li , all i
(<-|) :: Lit -> [Lit] -> [[Lit]]
l <-| ls = lf : lt where
lf = (inv l) : ls -- ~l or l1 or l2 ...
lt = [ [ l, inv li ] | li <- ls ] -- l or ~li , all i
atmostone l = [ [inv a, inv b] | (a:bs) <- tails l, b <- bs ]
dirconds n = concat [ atmostone [ dir i d | d <- [0..3]]
| i <- [0..n-1] ]
boundary p = (p<5) || (p>24) || (p `mod` 5 == 0)
positions = [ p | p<-[0..24], not (boundary p) ]
start = head positions
stop = last positions
wp = [ if boundary p then 0 else p - 4 - p `div` 5 | p <- [0..23]]
++ [1,0,0,0,0,0]
wallat :: Wall -> Int -> Bool
wallat w p = testBit (4*w+1) (wp!!p) -- (True:False:w) !! (wp!!p)
jump:: Int -> Int -> Int
jump pos dir = pos + ([-5,1,5,-1]!!dir)
freestep :: Wall -> Int -> Int -> Maybe Int
freestep w pos dir = let np = jump pos dir in
if wallat w np
then Nothing
else Just np
reach :: Wall -> Int -> [Int]
reach w p = [ np | Just np <- map (freestep w p) [0..3] ]
reachable :: Wall -> [Int]
reachable w = go [start] [start] where
go seen [] = seen
go seen front = let new = nub [ n | p <- front,
n <- reach w p,
n `notElem` seen ]
in go (seen++new) new
nicereachable :: Wall -> Maybe [Int]
nicereachable w =
let r = reachable w
in if and [ p `elem` r || wallat w p | p <- positions]
then Just r
else Nothing
mazestepdirposconds w n p d =
let ph = posh w (n+1) p d
conds = case freestep w p d of
(Just np) -> ph <-& [ pos w n np, dir n (opdir d) ]
Nothing -> ph <-& [ pos w n p, dir n d ]
in (ph,conds)
mazestepposconds w n p =
let cnds = map (mazestepdirposconds w n p) [0..3]
ps = pos w (n+1) p
in ( ps <-| (map fst cnds)) ++ (concatMap snd cnds)
mazestepconds w r n = concatMap (mazestepposconds w n) r
mazeconds w len r = [ pos w 0 start ] :
[ pos w i stop | i <- [6..len] ] :
(concat [ atmostone [ pos w s p | p <- positions ]
| s<-[0..len] ]) ++
(concatMap (mazestepconds w r) [0..len-1])
conds l = dirconds l ++
concat [ mazeconds w l r |
(w,Just r) <- [(i,nicereachable i)|i<-[0..2^14-1]]]
main = do
[n] <- getArgs
mapM_ print $ conds (read n)