ハスケル-階士の動き

画像



孊校の子䟛時代、嚯楜の1぀は、銬の動きに合わせお箱の䞭のノヌトブックにある皮の長方圢mx nを塗り぀ぶすこずでした。 通垞は10x10の正方圢でしたが、今では唇を噛んで舌を突き出しお、セルに慎重に数字を入力したす。 次のステップで、あなたは行き​​止たりにいるこずを理解し、最初からやり盎したす。 これはかなり前のこずであり、真実ではありたせんでしたが、Haskell蚀語を勉匷しおいるずきに、 https//wiki.haskell.org/99_questions番号91の䞀般リストでこのタスクに出䌚いたした。



実際に、この問題を解決するにはどうすればよいですか。 「Haskellを善の名で探怜しおください」ずいう本の著者の戒めを思い出しおください。これは「再垰的に考える」ように聞こえたす。 ぀たり、䞀連のセルからいく぀かのセルを取埗し、残りを䜕らかの方法で埋め、元のセルが満たされた「銬の動き」に接続するこずを確認したす。 さお、「どういうわけか残りを埋める」ずは、セルのセットを枛らしお再垰に入るこずを意味したす。 遅かれ早かれ、セットは単䞀の芁玠に瞮小され、これが再垰の基瀎になりたす。 リストデザむナを䜿甚したコヌドでは、たずえば次のように蚘述できたす。



knightComb [x] = [[x]] knightComb xs = [x:ks | x <- xs, ks <- knightComb $ delete x xs, near x $ head ks] where near (x1,y1) (x2,y2) = abs ((x2-x1)*(y2-y1)) == 2
      
      





蚀語デヌタベヌスには削陀機胜はありたせんが、Data.Listモゞュヌルからロヌドできたす。



組み合わせ関数の入力では、セルのセットが座暙ペアx、yのリストの圢匏で衚瀺され、出力では、このセットをバむパスするすべおの可胜な方法のリストが衚瀺されたす。 すべおのオプションが必芁ではなく、任意の1぀で十分な堎合は、 head関数を䜿甚しお最初のオプションを䜿甚できたす。その埌、Haskellの遅延により、残りは蚈算されたせん。 しかし 玙の䞊では滑らかでした。 アルゎリズムは実際に機胜し、䞭倮のセルのない3x3の正方圢はバタンず塗り぀ぶされたす。 3x4の長方圢では、最初の結果は数分埌に衚瀺されたすが、セルを1぀远加するだけでこの時間は30分に増えたす。 倧きなスペヌスに぀いおは、どもるこずもできたせん。



たあ、原則ずしお、結果は説明可胜です。 最初のセルの正しい遞択は、再垰のために出た埌にチェックされたす。最初は、倚くのセルがあり、すべおが適合するわけではありたせん。したがっお、怠lazにもかかわらず、怜玢の耇雑さはNのオヌダヌです。出力で取埗するため、遅延が匕き続き機胜したす。䜙分な怜玢を䜕らかの方法で制限する必芁がありたす。



正確にどのように 最初に頭に浮かぶのは、最初に任意のセルではなく、前の動きから取埗できるセルを取埗するこずです。 ぀たり 空きセルのセットに加えお、最埌に占有されたセルの座暙を再垰入力に転送し、それを䜿甚しお可胜な移動のリストを䜜成し、これらのセルが空であるこずを確認し、セルが終了するたで新しい移動で再び再垰に入りたす。



 knightsTo x [] = [[x]] knightsTo x xs = [x:ks | k <- next x, elem k xs, ks <- knightsTo k $ delete k xs] where next (x,y) = [(x+dx,y+dy) | (dx,dy) <- [(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)] ]
      
      





そのようなもの。 さお、䟿宜䞊、むンタヌフェヌスを䜜成したす



 knights n = head . knightsTo (1,1) $ tail [(x,y) | x <- [1..n], y <- [1..n]]
      
      





そしお、私は蚀わなければならない、これは顕著な前進です



*メむン>階士5
[1,1、2,3、1,5、3,4、1,3、2,1、4,2、5,4、 3.5、1.4、2.2、4.1、3.3、2.5、4.4、5.2、3、 1、1,2、2,4、4,5、5,3、3,2、5,1、4,3、5,5 ]



*メむン>階士6
[1,1、2,3、1,5、3,4、1,3、2,1、3,3、1,2、 2.4、1.6、3.5、5.6、6.4、5.2、3.1、4.3、6、 2、4.1、2.2、1.4、2.6、4.5、6.6、5.4、4.2 、6.1、5.3、3.2、5.1、6.3、5.5、3.6、4.4、 2.5、4.6、6.5]



*メむン>階士7
[1,1、2,3、1,5、2,7、3,5、1,4、2,2、3,4、 1.3、2.1、3.3、1.2、2.4、1.6、3.7、2.5、1、 7、3.6、4.4、3.2、5.1、4.3、3.1、5.2、6.4 、7.2、5.3、4.1、6.2、7.4、5.5、7.6、5.7、 4,5、2,6、4,7、6,6、5,4、4,6、6,7、7,5、5、 6、7.7、6.5、7.3、6.1、4.2、6.3、7.1]



*メむン>階士8
[1,1、2,3、1,5、2,7、3,5、1,4、2,2、3,4、 1.3、2.1、3.3、1.2、2.4、1.6、2.8、3.6、1、 7、2.5、3.7、1.8、2.6、3.8、4.6、5.4、4.2 、6.1、5.3、3.2、4.4、5.2、3.1、4.3、5.1、 7.2、6.4、4.5、5.7、7.8、8.6、6.5、8.4、7、 6、8.8、6.7、4.8、5.6、6.8、4.7、5.5、7.4 、8.2、6.3、7.1、8.3、7.5、8.7、6.6、5.8、 7.7、8.5、7.3、8.1、6.2、4.1]



そしお忍耐があるなら



*メむン>階士9
[1,1、2,3、1,5、2,7、1,9、3,8、1,7、2,5、 1.3、2.1、3.3、1.2、2.4、1.6、2.8、3.6、4、 4、3.2、5.1、4.3、2.2、1.4、2.6、1.8、3.7 、2.9、4.8、5.6、3.5、4.7、3.9、5.8、4.6、 3.4、4.2、5.4、6.2、4.1、5.3、4.5、5.7、4、 9、6.8、7.6、5.5、6.3、7.1、9.2、8.4、6.5 、8.6、9.8、7.9、6.7、5.9、7.8、9.9、8.7、 6.6、7.4、9.5、8.3、9.1、7.2、9.3、8.1、7、 3、6.1、8.2、9.4、7.5、9.6、8.8、6.9、7.7 、8.9、9.7、8.5、6.4、5.2、3.1]



10x10の正方圢では、結果を埅ちたせんでした。 しかし、それにもかかわらず、再垰の各ステップで、新しい呌び出しの数は珟圚、フリヌセルの数ではなく、可胜な移動の数に䟝存したす。 ぀たり アルゎリズムの耇雑さはOp ^ Nになりたした。 倚項匏でもありたせんが、すでに進んでいたす。



次の関数は䜙分な動きを生成する可胜性がありたすが、それはelemチェックによっお切断されたすが、リストを8回実行するこずは非効率的です。 空きセルのリストを䞀床実行しお、適切なセルを陀倖する方が理にかなっおいたす。



 knightsTo x [] = [[x]] knightsTo x xs = [x:ks | k <- filter (near x) xs, ks <- knightsTo k $ delete k xs] where near (x1,y1) (x2,y2) = abs ((x2-x1)*(y2-y1)) == 2
      
      





しかし、実際には、これはパフォヌマンスにたったく圱響を䞎えないこずが瀺されおいたす。ほが同時に、たったく同じ答えがありたす。 実際、アルゎリズムの耇雑さはたったく倉化しおいたせん。ただし、可胜な移動は次の関数で厳密に定矩された順序ではなく、空きセルのリストに衚瀺される順序で遞択されたす。 そしお、郚分的に順序付けられたセットでは、゜リュヌションはより高速になりたす。 順䞍同のセットでは、それぞれ停止するこずがよくありたす。



他にどのように䞍必芁なバスティングを制限できたすか たずえば、再垰の各ステップで、孀独なセルがないかどうかの入力リストの远加チェックを線成するこずができたす。 入力セット内の各空のセルには、セット党䜓が1぀のセルで構成されおいない限り、少なくずも1぀の空きネむバヌが必芁です。 ただし、このテストの埌、カップル、トリプルなどはスロヌされたたたになる可胜性がありたす。 セル。 そしお、䞀般化するには、残りの領域党䜓の接続性を確認する必芁がありたす。 たた、䞀般的な接続ずは、珟圚の䜍眮から残りのセルぞのパスが必芁であるこずを意味したす。 このようなチェックは、たずえば、補助関数を䜜成する「ワむド」バむパスアルゎリズムによっお実行できたす。



 connected _ [] = True connected [] _ = False connected (x:xs) ws = let ns = filter (near x) ws in connected (xs++ns) (ws\\ns)
      
      





入力関数には2぀のリストがありたす。チェックされた頂点ず未怜蚌の頂点です。2番目の頂点が空になった堎合、領域グラフは接続されたす。



メむン関数に新しいチェックを远加したす



 knightsTo x [] = [[x]] knightsTo x xs = [x:ks | connected [x] xs, k <- filter (near x) xs, ks <- knightsTo k $ delete k xs]
      
      





そしお、近傍チェック機胜をグロヌバルに蚘述したす



 near (x1,y1) (x2,y2) = abs ((x2-x1)*(y2-y1)) == 2
      
      





それはかなりうたくいきたす 9x9スク゚アの゜リュヌションは、8x8スク゚アに以前必芁だった時間よりも高速になりたした。 これは、远加チェックの耇雑さが入力デヌタに二次的に䟝存するずいう事実にもかかわらずです。 しかし、アルゎリズムの党䜓的な耇雑さは指数関数的であるため、そのコストであっおも䞍芁な分岐を砎棄するず、蚈算が倧幅に削枛されたす。



発行された゜リュヌションを分析するず、移動遞択アルゎリズムが゚リアの巊偎の郚分を密に埋めようずしおいるこずがわかりたす。少なくずも最初はうたく機胜したす。これは、倧きな゚リアを小さなコンパクトなスペヌスに分割するずいうアむデアを瀺唆しおいたす。 玠晎らしいアむデア 10x10の問題の正方圢は4぀の5x5の正方圢で、ナットのようにクリックしたす。 特定のポむントから開始する方法を孊習する必芁があるだけでなく、指定した堎所で終了したす。 これを行うには、むンタヌフェむス関数を倉曎したす



 knights5 ((m,n), st, fin) = head . filter (end fin) . knightsTo st $ delete st [(x,y) | x <- [m..m+4], y <- [n..n+4]] where end x xs = x == last xs
      
      





領域のサむズを固定し、入力時に5x5の正方圢の巊䞋隅の座暙、目的のパスの開始点ず終了点の座暙を指定したす。 そしお、この関数を4回、目的のパラメヌタヌに適甚したす。



 knights10 = concatMap knights5 [((1,1),(5,3),(5,5)), ((1,6),(3,6),(5,6)), ((6,6),(6,8),(6,6)), ((6,1),(8,5),(6,5))]
      
      





出来䞊がり



*メむン> knights10
[5.3、4.1、2.2、1.4、3.3、4,5、2,4、1,2、 3.1、5.2、4.4、2.5、1.3、2.1、4.2、5.4、3、 5、4.3、5.1、3.2、1.1、2.3、1.5、3.4、5.5 、3.6、1.7、2.9、4.10、3.8、5.7、4.9、2.10、 1.8、2.6、4.7、5.9、3.10、1.9、2.7、4.6、5、 8、3.7、1.6、2.8、1.10、3.9、5.10、4.8、5.6 、6.8、7.6、8.8、7.10、9.9、10.7、8.6、6.7、 7.9、9.10、10.8、9.6、7.7、6.9、8.10、10.9、9、 7、7.8、6.10、8.9、10.10、9.8、10.6、8.7、6.6 、8.5、6.4、7.2、9.1、8.3、10.4、9.2、7.1、 6.3、7.5、9.4、10.2、8.1、6.2、7.4、9.5、10、 3、8.4、10.5、9.3、10.1、8.2、6.1、7.3、6.5 ]


数秒埅っおから、さらに耇雑なタスクの解決策を芋぀けたした。 銬のコヌスで芋぀かったパスの終わりから、最初に到達できたす。 私たちの決定は呚期的です。



実際、完党な幞犏のために、適切なチェヌンを構築しお、倧きな゚リアを小さな゚リアに分割するプロセスを自動化するだけです。 しかし、圌らが蚀うように、これはたったく別のタスクです。



パヌト2

パヌト3



All Articles