// 解を列挙する関数
let solve xBlockNum yBlockNum =
let [xLen; yLen] = [xBlockNum; yBlockNum] |> List.map (fun n -> n * 2 - 1)
let markingNum = xBlockNum * yBlockNum * 2 - 1
let directions = [1, 0; 0, 1; -1, 0; 0, -1]
let memo = System.Collections.Generic.HashSet(HashIdentity.Structural)
let getNext markedSet candidates =
candidates |> Seq.map (fun ((x, y), (dx, dy)) ->
let nx, ny = x + dx, y + dy
let newMarked = markedSet |> Set.add (x, y) |> Set.add (nx, ny)
directions |> List.choose (fun (dx, dy) ->
if 1 <= nx + dx && nx + dx <= xLen && 1 <= ny + dy && ny + dy <= yLen
then Some((nx + dx, ny + dy), (dx, dy)) else None)
|> Seq.append candidates
|> Seq.filter (fun ((x, y), (dx, dy)) -> Set.contains (x + dx, y + dy) newMarked |> not)
|> fun nextCandidates -> newMarked, nextCandidates)
let rec solve markedSet candidates = seq {
if memo.Add markedSet then
if Set.count markedSet = markingNum then yield markedSet
else yield! getNext markedSet candidates |> Seq.collect ((<||) solve) }
solve (set [1, 1]) [(2, 1), (1, 0); (1, 2), (0, 1)]
|> Seq.map (fun result ->
[for y in 0 .. yLen + 1 ->
[for x in 0 .. xLen + 1 -> if Set.contains (x, y) result then "*" else "-"]])
// 解を10個表示
solve 4 4 |> Seq.take 10 |> Seq.iter (fun result ->
result |> Seq.iter (String.concat "" >> printfn "%s"); printfn "")
Ly8g6Kej44KS5YiX5oyZ44GZ44KL6Zai5pWwCmxldCBzb2x2ZSB4QmxvY2tOdW0geUJsb2NrTnVtID0KICAgIGxldCBbeExlbjsgeUxlbl0gPSBbeEJsb2NrTnVtOyB5QmxvY2tOdW1dIHw+IExpc3QubWFwIChmdW4gbiAtPiBuICogMiAtIDEpCiAgICBsZXQgbWFya2luZ051bSA9IHhCbG9ja051bSAqIHlCbG9ja051bSAqIDIgLSAxCiAgICBsZXQgZGlyZWN0aW9ucyA9IFsxLCAwOyAwLCAxOyAtMSwgMDsgMCwgLTFdCiAgICBsZXQgbWVtbyA9IFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXQoSGFzaElkZW50aXR5LlN0cnVjdHVyYWwpCgogICAgbGV0IGdldE5leHQgbWFya2VkU2V0IGNhbmRpZGF0ZXMgPQogICAgICAgIGNhbmRpZGF0ZXMgfD4gU2VxLm1hcCAoZnVuICgoeCwgeSksIChkeCwgZHkpKSAtPgogICAgICAgICAgICBsZXQgbngsIG55ID0geCArIGR4LCB5ICsgZHkKICAgICAgICAgICAgbGV0IG5ld01hcmtlZCA9IG1hcmtlZFNldCB8PiBTZXQuYWRkICh4LCB5KSB8PiBTZXQuYWRkIChueCwgbnkpCiAgICAgICAgICAgIGRpcmVjdGlvbnMgfD4gTGlzdC5jaG9vc2UgKGZ1biAoZHgsIGR5KSAtPgogICAgICAgICAgICAgICAgaWYgMSA8PSBueCArIGR4ICYmIG54ICsgZHggPD0geExlbiAmJiAxIDw9IG55ICsgZHkgJiYgbnkgKyBkeSA8PSB5TGVuCiAgICAgICAgICAgICAgICB0aGVuIFNvbWUoKG54ICsgZHgsIG55ICsgZHkpLCAoZHgsIGR5KSkgZWxzZSBOb25lKQogICAgICAgICAgICB8PiBTZXEuYXBwZW5kIGNhbmRpZGF0ZXMKICAgICAgICAgICAgfD4gU2VxLmZpbHRlciAoZnVuICgoeCwgeSksIChkeCwgZHkpKSAtPiBTZXQuY29udGFpbnMgKHggKyBkeCwgeSArIGR5KSBuZXdNYXJrZWQgfD4gbm90KQogICAgICAgICAgICB8PiBmdW4gbmV4dENhbmRpZGF0ZXMgLT4gbmV3TWFya2VkLCBuZXh0Q2FuZGlkYXRlcykKCiAgICBsZXQgcmVjIHNvbHZlIG1hcmtlZFNldCBjYW5kaWRhdGVzID0gc2VxIHsKICAgICAgICBpZiBtZW1vLkFkZCBtYXJrZWRTZXQgdGhlbgogICAgICAgICAgICBpZiBTZXQuY291bnQgbWFya2VkU2V0ID0gbWFya2luZ051bSB0aGVuIHlpZWxkIG1hcmtlZFNldAogICAgICAgICAgICBlbHNlIHlpZWxkISBnZXROZXh0IG1hcmtlZFNldCBjYW5kaWRhdGVzIHw+IFNlcS5jb2xsZWN0ICgoPHx8KSBzb2x2ZSkgfQoKICAgIHNvbHZlIChzZXQgWzEsIDFdKSBbKDIsIDEpLCAoMSwgMCk7ICgxLCAyKSwgKDAsIDEpXQogICAgfD4gU2VxLm1hcCAoZnVuIHJlc3VsdCAtPgogICAgICAgIFtmb3IgeSBpbiAwIC4uIHlMZW4gKyAxIC0+CiAgICAgICAgICAgIFtmb3IgeCBpbiAwIC4uIHhMZW4gKyAxIC0+IGlmIFNldC5jb250YWlucyAoeCwgeSkgcmVzdWx0IHRoZW4gIioiIGVsc2UgIi0iXV0pCgovLyDop6PjgpIxMOWAi+ihqOekugpzb2x2ZSA0IDQgfD4gU2VxLnRha2UgMTAgfD4gU2VxLml0ZXIgKGZ1biByZXN1bHQgLT4KICAgIHJlc3VsdCB8PiBTZXEuaXRlciAoU3RyaW5nLmNvbmNhdCAiIiA+PiBwcmludGZuICIlcyIpOyBwcmludGZuICIiKQ==