스도쿠 킹의 투어 극대화


16

배경

스도쿠× 격자가 크기가 인 상자로 나뉘어져 있으면 1 에서 까지 의 각 숫자가 각 행, 열 및 상자에 정확히 한 번 표시되어야 하는 숫자 퍼즐 입니다.

체스 게임에서 은 한 번에 8 개의 인접한 셀 중 하나로 이동할 수 있습니다. 여기서 "인접한"은 수평, 수직 또는 대각선으로 인접한 것을 의미합니다.

왕의 투어 기사의 투어의 비유입니다; 그것은 체스 킹의 움직임으로 주어진 보드에서 정확히 한 번 모든 셀을 방문하는 (아마도 열린) 경로입니다.

직무

6x6 스도쿠 그리드를 고려하십시오.

654 | 321
123 | 654
----+----
462 | 135
315 | 246
----+----
536 | 412
241 | 563

그리고 왕의 여행 (에서 01까지 36) :

01 02 03 | 34 35 36
31 32 33 | 04 05 06
---------+---------
30 23 28 | 27 26 07
22 29 24 | 25 09 08
---------+---------
21 19 16 | 10 14 13
20 17 18 | 15 11 12

둘러보기는 36 자리 숫자 654654564463215641325365231214123321입니다.

다른 왕의 여행을하는 것은 더 큰 숫자를 준다. 예를 들어, 위의 경로 65<6>56446556...보다 확실히 큰 경로로 찾을 수 있습니다 . 더 높은 숫자를 얻기 위해 스도쿠 보드를 변경할 수 있습니다.

... | ...
.6. | ...
----+----
..6 | ...
.5. | 6..
----+----
.45 | .6.
6.. | 5..

이 불완전한 보드는 시작 666655546...순서가 9 자리의 최적 시작 순서입니다 .

귀하의 작업은 3 x 3 상자가있는 표준 9 x 9 스도쿠에서 가장 큰 숫자찾는 것입니다 .

... | ... | ...
... | ... | ...
... | ... | ...
----+-----+----
... | ... | ...
... | ... | ...
... | ... | ...
----+-----+----
... | ... | ...
... | ... | ...
... | ... | ...

참고 이 문제가 아닌 ; 초점은 이론적으로 작동하는 작은 프로그램을 작성하는 것이 아니라 실제로 솔루션을 찾는 것입니다.

득점 및 당첨 기준

제출 점수는 프로그램에서 찾은 81 자리 숫자입니다. 가장 높은 점수를받은 제출이 승리합니다. 프로그램은 또한 스도쿠 그리드와 왕의 여행을 사람이 읽을 수있는 형태로 출력해야합니다. 제출물에 포함 시키십시오.

프로그램이 여러 결과를 출력 할 수 있습니다. 당신의 점수는 최대입니다.

프로그램에는 시간 제한이 없습니다. 프로그램이 계속 실행되고 이후에 더 높은 숫자를 찾으면 게시물을 편집하여 제출 점수를 업데이트 할 수 있습니다. Tiebreaker는 점수를 달성하기위한 가장 빠른 시간입니다 (예 : 게시 시간 (아직 편집하지 않은 경우) 또는 점수가 업데이트 된 경우 (또는 그렇지 않은 경우))


2
Best of PPCG에 대한 이 도전에 대한 귀하의 자체 추천에서 , "이것은 아마도 코드 길이 등과 같은 점수가 아닌 최적화 된 솔루션을 직접 요청하는 최초의 [코드 도전"일 것입니다. " 나는 그것이 사실이 아님을 알려 드리고 싶었 습니다. 2015 년에 게시 된 Shortest Universal Maze Exit String 이 있습니다.
Esolanging Fruit

답변:


19

Python + Z3 , 999899898789789787876789658767666545355432471632124566352413452143214125313214321, 최적

약 30 분 안에 작동하며

1 3 4 8 9 7 6 2 5
2 9 7 1 5 6 8 3 4
5 6 8 4 2 3 7 9 1
4 7 6 2 1 5 9 8 3
8 5 1 6 3 9 2 4 7
9 2 3 7 8 4 1 5 6
3 8 5 9 6 1 4 7 2
6 4 9 5 7 2 3 1 8
7 1 2 3 4 8 5 6 9
81 79 78 14 15 16 54 57 56
80 12 13 77 52 53 17 55 58
34 33 11 51 76 75 18  1 59
35 10 32 50 74 72  2 19 60
 9 36 49 31 73  3 71 61 20
 8 48 37 30  4 69 70 62 21
47  7 38  5 29 68 65 22 63
46 43  6 39 28 67 66 64 23
44 45 42 41 40 27 26 25 24
999899898789789787876789658767666545355432471632124566352413452143214125313214321

암호

import z3


def adj(a):
    x, y = a
    for x1 in range(max(0, x - 1), min(9, x + 2)):
        for y1 in range(max(0, y - 1), min(9, y + 2)):
            if (x1, y1) != a:
                yield x1, y1


solver = z3.SolverFor("QF_FD")

squares = list((x, y) for x in range(9) for y in range(9))
num = {(x, y): z3.Int(f"num{x}_{y}") for x, y in squares}
for a in squares:
    solver += 1 <= num[a], num[a] <= 9
for cells in (
    [[(x, y) for y in range(9)] for x in range(9)]
    + [[(x, y) for x in range(9)] for y in range(9)]
    + [
        [(x, y) for x in range(i, i + 3) for y in range(j, j + 3)]
        for i in range(0, 9, 3)
        for j in range(0, 9, 3)
    ]
):
    solver += z3.Distinct([num[x, y] for x, y in cells])
    for k in range(1, 10):
        solver += z3.Or([num[x, y] == k for x, y in cells])

move = {
    ((x0, y0), (x1, y1)): z3.Bool(f"move{x0}_{y0}_{x1}_{y1}")
    for x0, y0 in squares
    for x1, y1 in adj((x0, y0))
}
tour = {(x, y): z3.Int(f"tour{x}_{y}") for x, y in squares}
for a in squares:
    solver += 0 <= tour[a], tour[a] < 81
for a in squares:
    solver += z3.PbEq([(move[a, b], 1) for b in adj(a)] + [(tour[a] == 80, 1)], 1)
for b in squares:
    solver += z3.PbEq([(move[a, b], 1) for a in adj(b)] + [(tour[b] == 0, 1)], 1)
solver += z3.Distinct([tour[a] for a in squares])
for t in range(81):
    solver += z3.Or([tour[a] == t for a in squares])
for a in squares:
    for b in adj(a):
        solver += move[a, b] == (tour[a] + 1 == tour[b])

value = [z3.Int(f"value{t}") for t in range(81)]
for t in range(81):
    solver += 1 <= value[t], value[t] <= 9
for a in squares:
    for t in range(81):
        solver += z3.Implies(tour[a] == t, num[a] == value[t])

assert solver.check() != z3.unsat
opt = 0
while opt < 81:
    model = solver.model()
    for y in range(9):
        print(*(model[num[x, y]] for x in range(9)))
    for y in range(9):
        print(*(f"{model[tour[x, y]].as_long() + 1:2}" for x in range(9)))
    best = [model[value[t]].as_long() for t in range(81)]
    print(*best, sep="")
    print()
    while opt < 81:
        improve = z3.Bool(f"improve{opt}_{best[opt]}")
        solver += improve == (value[opt] > best[opt])
        if solver.check(improve) != z3.unsat:
            break
        solver += value[opt] == best[opt]
        opt += 1

분명히 나는 ​​문제를 너무 과대 평가했다. 그리고 나는 Z3의 어두운 마법을 완전히 잊어 버렸습니다 ...
Bubbler

@ 버블 러는 최적의 솔루션이 도달하기 어렵다는 것을 확신합니다. 나 자신 같은 실수를 한 - 누군가 최적의 솔루션을 ... 게시하기 전에 광산은 더 적은 시간을 지속 codegolf.stackexchange.com/a/51974/20283
trichoplax

광산은 복구 가능한 아니지만,이 문제가 더 큰 보드에 변화와 (아마도 이것에 다시 연결 문제에 대한 후속) 다른 체스 조각으로 일할 수 있는지 궁금해
trichoplax을
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.