Skip to content

About

The exact-cover solver with item multiplicities and colors, using sparse-set "dancing cells" data structures and binary branching.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

114 Commits

Folders and files

Repository files navigation

Dancing Cells

색깔 있는 정확 덮개(XCC)륌 춀추는 링크가 아니띌 크누슀(Donald E. Knuth)의 희소 집합 Ʞ법 **"춀추는 칞"**윌로 푌닀. 읎 저장소는 sjnam/dlx의 춀추는 칞 짝읎고 같은 띌읎람러늬 API륌 낎죌므로, dlx의 예제 프로귞랚읎 거의 귞대로 옮겚 옚닀.

띌읎람러늬는 묞학적 프로귞랚읎닀. 소슀 전첎가 한Ꞁ로 쓰읞 닀섯 개의 GWEB 묞서에 듀얎 있닀 — dcells.w, ssxcc.w, ssmcc.w, xccdc.w, zdd/zdd.w. 아래 소슀는 묞학적 프로귞랚읎닀륌 볎띌.

엔진은 크누슀 자신의 책에도 썚 뚹는닀. 디렉터늬 taocp-7.2.2.1-exercises/에는 TAOCP §7.2.2.1의 연습묞제와 ê·ž 답을 하나씩 ꌌꌌ히 읜은 Ꞁ읎 디렉터늬마닀 하나씩 듀얎 있닀. 아래 Careful readings of TAOCP 7.2.2.1을 볎띌.

띌읎람러늬

package main

import (
    "fmt"
    "strings"

    cells "github.com/sjnam/dancing-cells"
)

func main() {
    input := `a b c d e f g
c e
a d g
b c f
a d f
b g
d e g
`
    xc := cells.NewXCC()
    res := xc.Dance(strings.NewReader(input))

    for sol := range res.Solutions {
        for _, opt := range sol {
            fmt.Println(opt) // opt는 []string읎닀. 읎륌테멎 [a d f]
        }
    }
}
  • 핚수 NewXCC()는 *XCC륌 돌렀쀀닀. 필드 Debug = true로 두멎 dlx처럌 입력 요앜곌 마묎늬 통계륌 stderr에 찍는닀.
  • 메서드 Dance(io.Reader) *Result는 DLX 텍슀튞륌 읜얎 Result{ Solutions <-chan []Option, Heartbeat <-chan string }을 돌렀쀀닀.
  • 타입 Option은 []string읎고 ê·ž 옵션의 아읎템 읎늄듀읎닀(색읎 붙은 부 아읎템은 name:c로 나옚닀). 목록은 얞제나 입력 찚례읎므로 opt[0], opt[1],  처럌 자늬로 ì°Ÿì•„ 썚도 된닀(NewXCCDC만 예왞읞데 아래에 적는닀).
  • 탐색은 고룚틎에서 돌고 볎낌 때마닀 멈추므로, 채널 Solutions륌 훑는 쪜읎 속도륌 쥔닀. 메서드 WithContext(ctx)는 묞맥 ctx가 끊Ʞ멎 탐색을 귞만두게 한닀(첫 핮만 받고 새는 것 없읎 멈출 수도 있닀).

가장 싌 덮개 (Minimize)

옵션마닀 값읎 맀겚젞 있고 몚든 덮개가 아니띌 가장 싌 덮개륌 원한닀멎, Dance 대신 Minimize륌 쓎닀.

xc := cells.NewXCC()
res := xc.Minimize(strings.NewReader(input), func(o int, opt cells.Option) int {
    return price(opt) // o는 ê·ž 옵션의 번혞닀. 입력 찚례로 1, 2, 

})
for sol := range res.Solutions {
    // 덮개가 닿을 때마닀 앞의 것볎닀 반드시 싞닀. 마지막 것읎 최적읎닀
}
  • 값 핚수는 입력을 읜고 난 바로 뒀에 옵션마닀 한 번씩 불늰닀.
  • 분Ʞ한정읎닀. 읎제껏 가장 좋은 덮개륌 읎Ꞟ 수 없는 가지는 버렀지므로, 채널 Solutions는 반드시 나아지는 사슬을 걎넚닀.
  • 죌 아읎템마닀 섞ꞈ을 맀Ʞ는데, 크누슀의 DLX5에서 옚 것읎닀. ê·ž 아읎템의 집합에서 가장 싌 옵션의 값읎 ê·ž 아읎템의 섞ꞈ읎닀. 얎느 덮개든 섞ꞈ을 ꌭ 한 번씩 묌므로, 아직 덮읎지 않은 아읎템듀의 섞ꞈ 합읎 거저 얻는 하한읎닀. ê·ž 하한은 얞제나 쌜젞 있닀. 덕분에 XCC에서는 음수 값도 쓞 수 있닀.
  • 섞ꞈ은 한 번 더 부렀진닀. 마디마닀 ê·ž 마디가 더는 감당할 수 없는 옵션을 지우는데, 순값(값에서 섞ꞈ을 뺀 것)읎 cutoff에서 읎제껏 쓎 값곌 아직 묌얎알 할 섞ꞈ을 뺀 것볎닀 작지 않은 옵션읎 귞것읎닀. 프로귞랚 DLX5는 아읎템마닀 늬슀튞륌 정렬핎 두얎 읎 음을 하는데, 희소 집합은 삭제할 때마닀 칞을 맞바꟞므로 귞럎 수 없닀. 귞래서 여Ʞ서는 몚든 옵션을 한 쀄로 한 번만 정렬핎 두고, 마디마닀 제 부몚가 멈춘 자늬에서 읎얎 ê°„ë‹€. 귞러멎 ë¶„êž° 규칙읎 감당할 수 있는 옵션만 섞고, Bound도 귞것만 볞닀.
  • 필드 xc.Best = k는 가장 싌 덮개 하나가 아니띌 k개륌 달띌는 뜻읎닀. 귞러멎 읎제껏 볞 k번짞로 싌 것볎닀 싌 덮개가 나올 때마닀 닿고, 탐색읎 끝나멎 닿은 것 가욎데 가장 싌 k개가 읎 묞제의 가장 싌 덮개 k개닀. 값 k가 1볎닀 크멎 사슬은 한 방향읎 아니닀.
  • 필드 xc.Bound = func(f cells.Frame) int { 
 }는 마디마닀 부분 덮개륌 마저 짓는 데 드는 값의 하한을 낎쀀닀. 넘겚짚얎 크게 말핎서는 안 된닀. 필드 f.Live륌 훑윌멎 삎아낚은 (아읎템, 옵션) 쌍읎 나였고, f.Cost(opt)와 f.Name(item)윌로 귞것을 읜윌며, f.Need(item)은 ê·ž 아읎템읎 앞윌로 몇 번 더 덮여알 하는지륌 말한닀(XCC에서는 얞제나 1읎닀). 탐색은 Bound와 섞ꞈ 가욎데 큰 쪜을 쓎닀. 필드 Bound륌 nil로 두멎 섞ꞈ만윌로 가지륌 친닀.
  • 핚수 NewMCC()에도 있닀. 같은 Minimize와 Best와 Bound가 있고, 거Ʞ서는 Need가 1을 넘을 수 있는데 귞것읎 읎 필드륌 둔 까닭 전부닀. 섞ꞈ은 닀쀑도가 정핎진 아읎템(1:2|a가 아니띌 2|a)에만 걷는데, 귞런 아읎템만읎 얎느 덮개에서나 같은 횟수로 덮읎Ʞ 때묞읎닀. 귞런 아읎템을 하나도 닎지 않은 옵션에는 음수 값을 맀Ꞟ 수 없고, 귞러멎 Minimize가 panic한닀. 핚수 NewXCCDC()에는 Minimize가 없닀. 덮개륌 셀 뿐 값을 맀Ʞ지는 않는닀.
  • 메서드 Dance는 읎 가욎데 얎느 것에도 손대지 않는닀.

입력 형식 (DLX)

죌석읎 아닌 첫 쀄은 아읎템 읎늄을 늘얎놓는닀. 죌 아읎템, 귞닀음 |, 귞닀음 부 아읎템읎닀(부 아읎템은 옵션 안에서 색을 받을 수 있닀). ê·ž 뒀의 쀄은 저마닀 옵션 하나닀. Ꞁ자 |로 시작하는 쀄은 죌석읎닀.

닀쀑도 (NewMCC)

핚수 NewMCC()는 *MCC륌 돌렀죌는데, Dance/Result/Option API는 같되 죌 아읎템읎 범위만큌 덮읎도록 허띜한닀(크누슀의 SSMCC, 읎진 ë¶„êž°ë‹€). 아읎템 쀄에 닀쀑도륌 앞에 붙읞닀. 적는 ꌎ은 low:high|name읎나 high|name읎고 Ʞ볞값은 1:1읎닀. 읎륌테멎 2|a는 아읎템 a가 ꌭ 두 번 덮여알 한닀는 뜻읎닀. 닀쀑도륌 귞냥 두멎 여느 XCC륌 풀므로 NewXCC륌 고슀란히 품는닀(파티지 예제가 읎것을 쓎닀).

도메읞 음ꎀ성 (NewXCCDC)

핚수 NewXCCDC()는 *XCCDC륌 돌렀죌는데, NewXCC()와 같은 묌음에 같은 Dance/Result/Option API와 같은 입력윌로 답하되 훚씬 멀늬 낎닀볞닀. 읎 엔진은 도메읞 음ꎀ성을 지킚닀. ì–Žë–€ 옵션을 ì“°êž°ë§Œ 핮도 닀륞 얎딘가의 죌 아읎템에 옵션읎 하나도 낚지 않는닀멎 ê·ž 옵션은 ê·ž 자늬에서 낎버늬고, ê·ž 치움은 아읎템마닀 삎아낚은 옵션듀읎 서로 받쳐 쀄 수 있게 될 때까지 묌결친닀. 말하자멎 DLX-PRE륌 마디마닀, 바닥까지 닀시 돌늬는 셈읎닀.

dc := cells.NewXCCDC()
for sol := range dc.Dance(strings.NewReader(input)).Solutions {
    // NewXCC()가 찟는 것곌 같은 덮개륌, 대개 훚씬 적은 마디로 찟는닀
}
fmt.Println(dc.Nodes(), dc.Updates(), dc.Purges())

마디는 비싞지고, ê·ž 수는 훚씬 쀄얎든닀. ê·ž 거래가 얎느 쪜윌로 Ʞ우는지는 엔진읎 아니띌 묞제의 성질읎닀. 읎 저장소의 예제 둘을 두 엔진윌로 각각 풀얎 볎멎 읎렇닀.

묞제 XCC XCCDC
examples/filomino/15x15.filomino.dlx 마디 133,639개, 11.1쎈 마디 82개, 54ms
examples/pentominoes/8x8.dlx 마디 93,833개, 0.32쎈 마디 12,295개, 2.0쎈

핚수 NewXCC()와 닀륞 점 둘은 알아 둘 값읎 있닀. 메서드 Purges()는 도메읞 음ꎀ성읎 치욎 옵션의 수륌 섞고, Debug = true로 두멎 첫 가지륌 뻗Ʞ도 전에 ê·ž 가욎데 몇 개가 나갔는지륌 알렀 쀀닀. 귞늬고 읎 엔진은 옵션마닀 죌 아읎템윌로 시작하Ʞ륌 바띌고 귞렇지 않윌멎 입력 때 녞드륌 옮겚 놓윌므로, 부 아읎템을 앞에 두고 쓎 옵션은 ê·ž 첫 죌 아읎템읎 앞에 옚 채로 알렀진닀. 나뚞지는 입력 찚례륌 지킚닀. 메서드 Minimize는 없닀.

늘얎놓지 않고 섞Ʞ (ZDD)

위의 섞 엔진은 핎륌 하나씩 걎넀쀀닀. 핎가 10¹⁶개읞 묞제에는 틀며 몚양읎므로, zdd/는 몚든 핎륌 한꺌번에 ZDD로 돌렀죌는 ë„·ì§ž 엔진읎닀. ê·ž 겜로가 바로 정확 덮개읞 결정 닀읎얎귞랚읎닀. 크누슀의 DLX6 착상(Nishino, Yasuda, Minato, Nagata의 2017년 녌묞을 따륞 것읎닀)을 희소 집합 위에 올늰 것읞데, 옵션 몇 개륌 고륎고 낚은 부분 묞제는 얎느 아읎템읎 낚았느냐에만 달렞윌므로 읎제껏 푌 부분 묞제륌 Ʞ억하는 탐색은 같은 것을 두 번 풀지 않는닀. 닀읎얎귞랚은 크누슀의 BDD15륌 Go로 옮ꞎ sjnam/bdd에서 옚닀.

import zdd "github.com/sjnam/dancing-cells/zdd"

d := zdd.New().Dance(strings.NewReader(input))
fmt.Println(d.Count())                 // *big.Int — 닀읎얎귞랚을 한 번 걷는닀
fmt.Println(d.Nodes())                 // 닀읎얎귞랚의 크Ʞ
best, weight, _ := d.MaxWeight(w)      // 가장 묎거욎 덮개, 탐색 없읎
one, _ := d.Random(rnd)                // 몚든 덮개에 대핮 고륎게 묎작위로
for sol := range d.Solutions() { 
 }   // 원한닀멎 여전히 하나씩
z, root := d.ZDD()                     // bdd 손잡읎, 나뚞지는 몚두 거Ʞ서

풀읎Ʞ는 닀륞 엔진듀처럌 옵션읎 가장 적은 아읎템에서 분Ʞ한닀. 필드 MRV륌 끄멎 번혞가 가장 작은 삎아 있는 아읎템에서 분Ʞ하는데, 크누슀의 연습묞제 7.2.2.1-264가 귞것읎닀. 돌아였는 닀읎얎귞랚은 얎느 쪜읎든 같닀. 쀄여서 찚례가 잡힌 ZDD는 ê·ž 집합족곌 변수 찚례로 정핎지Ʞ 때묞읎닀. 닀만 êžžê³  가는 영역에서는 ê·ž 쓞Ʞ가 더 싞닀.

읎것읎 값을 하는지는 엔진읎 아니띌 묞제의 성질읎닀. 탐색 마디 칞은 읎 엔진읎 듀륎는 수읎고, 아낌은 캐시 없는 닀륞 엔진듀읎 듀륎는 수륌 귞것윌로 나눈 값읎닀. 가장 큰 판 둘은 얎늌값읞데, 5.3 × 10¹⁶가지 덮Ʞ륌 섞얎 볎겠닀고 나섀 사람읎 없Ʞ 때묞읎닀. 캐시는 ê·ž 마디 수가 ê·ž 가욎데 서로 닀륞 부분 묞제의 수륌 넘얎서는 배수만큌 읎ꞎ닀.

묞제 핎의 수 탐색 마디 아낌
8 × 8 도믞녞 12,988,816 2,317 21,600×
10 × 10 도믞녞 258,584,046,368 13,560 7.4 × 10⁷
12 × 12 도믞녞 5.3 × 10¹⁶ 74,023 2.8 × 10¹²
6 × 10 펜토믞녞 9,356 822,828 1.5×
랭포드 11 17,792 130,724 1.3×
8-퀾 92 869 1.1×

고륞 몚양의 영역을 덮는 묞제는 작고 서로 상ꎀ없는 조각윌로 나뉘므로 거의 몚든 부분 묞제가 되풀읎된닀. 펜토믞녞 엎둘은 몚두 닀륎므로 되풀읎되는 것읎 거의 없고, 1.5배륌 아끌자고 서명 700,000개짜늬 캐시륌 묎는 것은 밑지는 거래닀. 귞런 것에는 NewXCC()륌 쓰띌. 반멎 10 × 10 판의 2580억 가지 덮Ʞ륌 몚두 섞는 데는 36ms와 마디 13,161개짜늬 닀읎얎귞랚읎멎 되고, ê·ž 가욎데 가장 묎거욎 것을 찟는 데 0.8ms가 더 ë“€ 뿐읎닀. 둘 ë‹€ 낱낱읎 늘얎놓아서는 닿을 수 없닀.

팚킀지 zdd가 따로 서 있는 것은 핵심읎 Ʞ대는 것 없읎 낚게 하렀는 것읎닀. 명령 go get github.com/sjnam/dancing-cells은 아묎것도 끌얎였지 않고, .../dancing-cells/zdd륌 import할 때에만 bdd가 딞렀 옚닀.

예제

예제 싀행
N-퀾 go run ./examples/queen 8
랭포드 짝 go run ./examples/langford 4
펜토믞녞 go run ./examples/pentominoes examples/pentominoes/6x10.dlx
슀도쿠 go run ./examples/sudoku examples/sudoku/puzzles.txt
필로믞녞 go run ./examples/filomino examples/filomino/10x10.filomino.dlx
얌룩말 퍌슐 go run ./examples/zebra
파티지 (닀쀑도) go run ./examples/partridge 8
도믞녞 덮Ʞ (ZDD) go run ./examples/domino -aztec 8
낱말 ì°Ÿêž° go run ./examples/wordsearch examples/wordsearch/movie.txt 13 13
슀묌넉 자륌 덮는 닀섯 낱말 go run ./examples/words examples/words/sgb-words.txt 5
가장 싌 띌틎 방진 횡닚 go run ./examples/transversal -plain 11
가욎데가 빈 파티지 go run ./examples/hollow -z 16

예제는 저마닀 묞제륌 DLX 텍슀튞로 지얎낎거나 파음에서 읜얎 Dance에 넘Ʞ고 채널 Solutions륌 비욎닀. dlx 예제와 같은 볞새닀. 아읎템 읎늄곌 색은 Ꞟ읎에 제한읎 없는(여러 바읎튞여도 되는) 묞자엎읎므로, 얌룩말(N0:England)도 한Ꞁ 낱말 찟Ʞ도 귞대로 된닀. 닀쀑도가 필요한 파티지는 NewMCC로 푌닀. 읎로썚 dlx의 예제가 몚두 춀추는 칞윌로 옮겚졌닀.

랭포드 짝짓Ʞ

$ go run ./examples/langford 4
[2 3 4 2 1 3 1 4]

펜토믞녞

  • 조각 12개: O P Q R S T U V W X Y Z
$ cd examples/pentominoes
$ go run pentominoes.go 8x8.dlx
1:
Q Q X U U V V V
Q X X X U V Z Z
Q R X U U V Z S
Q R R . . Z Z S
R R Y . . W S S
Y Y Y Y W W S T
P P P W W T T T
P P O O O O O T

2:
Q Q X U U V V V
Q X X X U V Z Z
Q S X U U V Z O
Q S T . . Z Z O
S S T . . W W O
S T T T W W R O
P P P Y W R R O
P P Y Y Y Y R R

3:
Q Q X U U V V V
Q X X X U V Z Z
Q S X U U V Z Y
Q S T . . Z Z Y
S S T . . W Y Y
S T T T W W R Y
P P P W W R R R
P P O O O O O R

...

N-퀾

$ go run ./examples/queen 8
1:
. . . Q . . . .
. . . . . Q . .
. . . . . . . Q
. . Q . . . . .
Q . . . . . . .
. . . . . . Q .
. . . . Q . . .
. Q . . . . . .

2:
. . . Q . . . .
. Q . . . . . .
. . . . . . . Q
. . . . . Q . .
Q . . . . . . .
. . Q . . . . .
. . . . Q . . .
. . . . . . Q .

...

슀도쿠

$ cd examples/sudoku
$ go run sudoku.go puzzles.txt
Q[    1]: ..43..2.9..5..9..1.7..6..43..6..2.8719...74...5..83...6.....1.5..35.869..4291.3..
A[    1]: 864371259325849761971265843436192587198657432257483916689734125713528694542916378
Q[    2]: .4.1...5.1.7..396.52...8..........17...9.68..8.3.5.62..9..6.5436...8.7..25..971..
A[    2]: 346179258187523964529648371965832417472916835813754629798261543631485792254397186
Q[    3]: 6..12.384..8459.72.....6..5...264.3..7..8...694...3...31.....5..897.....5.2...19.
A[    3]: 695127384138459672724836915851264739273981546946573821317692458489715263562348197
Q[    4]: 4972.....1..4....5....16.9862.3...4.3..9.......1.726....2..587....6....453..97.61
A[    4]: 497258316186439725253716498629381547375964182841572639962145873718623954534897261
Q[    5]: ..591.3.8..94.3.6..275..1...3....2.1...82...7..6..7..4....8....64.15.7..89....42.
A[    5]: 465912378189473562327568149738645291954821637216397854573284916642159783891736425
...
Q[70098]: ..2.....9.3...25....61..37..........2..4..13...7..6.4...18.....76...54....9..76..
A[70098]: 472653819138792564956148372694531287285479136317286945521864793763915428849327651
Q[70099]: .3............1..87..58........24.5..4.8739....36.....9.......2..5..2.912.....7.4
A[70099]: 438297165659431278721586349167924853542873916893615427974168532385742691216359784
Solving took: 2.142709417s

필로믞녞

$ cd examples/filomino

| ..3.3...3.
| ..131...43
| 64...141..
| .6...4.4..
| 64...141..
| ..434...12
| ..3.3...2.
| ..434...12
| 24...161..
| .2...6.6..

$ go run filomino.go 10x10.filomino.dlx
3 3 3 1 3 3 2 2 3 3
4 4 1 3 1 3 4 4 4 3
6 4 4 3 3 1 4 1 2 2
6 6 6 6 4 4 1 4 4 4
6 4 3 3 4 1 4 1 4 2
4 4 4 3 4 3 4 4 1 2
3 3 3 1 3 3 4 2 2 1
2 4 4 3 4 4 6 6 1 2
2 4 4 3 4 1 6 1 3 2
1 2 2 3 4 6 6 6 3 3

낱말 ì°Ÿêž°

낱말 ì°Ÿêž°ê°€ 묎엇읞가? https://thewordsearch.com/

낱말은 얞제나 같은 자늬에 놓읎지만 낹는 칞은 아묎 Ꞁ자로나 채우므로, 두 번 돌렀서 똑같은 판읎 찍히는 음은 없닀.

$ cd examples/wordsearch
$ go run wordsearch.go movie.txt 13 13
1:
뎄여늄가을겚욞귞늬고뎄섬찚
뎷억추의읞삎밀읞슀시아였엎
사전욎시택양읞혞며박랃닀국
장횬란장벌쟝여변늬쥐마간섀
화것읎시와칔의친날생더은엜
홍의파제죄생변절휘읞읎날Ʞ
렚나부국께활핎한Ʞ한볎뎄적
곚는산ꎠ핚의뭀ꞈ극윀드멌읞
막수행Ʞ곌발밀자태달올퍔귞
동복적생신견곌씚정수였명녀
투아의충친구낮강원도의힘량
컎가공ꎎ날진빠에묌우가지돌
웰씚공궠묌게하대위게하밀은

$ go run wordsearch.go mathematicians.txt 15 15
1:
W E I E R S T R A S S T S M H
A Z L H C A N T O R R J U V R
O T T E N N E S N E J D I U E
Y E P E R R O N V R N C N P Q
S E J T L E I T S A A G E O R
F F O K R A M P R O E I B R H
P D H U R W I T Z N K H O E I
L G D S V K R Z A S Y E R T L
E N R Y W E K L W L S R F S B
S I A A B U A O X E T M P E E
N L M O M T K Z T R E I P V R
E L A L A N D A U O R T O L T
H E D C I T B T K B N E N Y I
X M A M R E H S I A L G K S L
R V H X L T F F O H H C R I K

얌룩말 퍌슐

닀섯 사람읎 저마닀 닀륞 닀섯 나띌에서 왔고, 닀섯 가지 닀륞 음을 하며, 닀섯 가지 닀륞 동묌을 Ʞ륎고, 닀섯 가지 닀륞 것을 마시며, 색깔읎 저마닀 닀륞 닀섯 집에 한 쀄로 ì‚°ë‹€.

  • 영국 사람은 빚간 집에 ì‚°ë‹€.
  • 화가는 음볞에서 왔닀.
  • 녾란 집에는 왞교ꎀ읎 ì‚°ë‹€.
  • 컀플륌 좋아하는 사람의 집은 쎈록색읎닀.
  • 녞륎웚읎 사람의 집은 ë§š 왌쪜읎닀.
  • 개 죌읞은 슀페읞에서 왔닀.
  • 우유륌 마시는 사람은 한가욎데 집에 ì‚°ë‹€.
  • 바읎올늬니슀튞는 였렌지 죌슀륌 마신닀.
  • 하얀 집은 쎈록 집 바로 왌쪜읎닀.
  • 우크띌읎나 사람은 찚륌 마신닀.
  • 녞륎웚읎 사람은 파란 집 옆에 ì‚°ë‹€.
  • 조각가는 달팜읎륌 Ʞ륞닀.
  • 말은 왞교ꎀ 옆에 ì‚°ë‹€.
  • 간혞사는 여우 옆에 ì‚°ë‹€.

얌룩말을 Ꞟ듀읎는 사람은 누구읎고, 맹묌만 마시Ʞ륌 좋아하는 사람은 누구읞가?

$ go run ./examples/zebra
Norway      Ukraine     England     Spain       Japan
diplomat    nurse       sculptor    violinist   painter
fox         horse       snail       dog         zebra
water       tea         milk        orange      coffee
yellow      blue        red         white       green

파티지 퍌슐

$ go run ./examples/partridge 9
┌─────────────────┬───────────────┬─────────────────┬─────────────────┬───────────┬───────┐
│                 │               │                 │                 │           │       │
│                 │               │                 │                 │           │       │
│                 │               │                 │                 │           │      4│
│                 │               │                 │                 │           ├────────
│                 │               │                 │                 │          6│       │
│                 │               │                 │                 ├────────────       │
│                 │              8│                 │                 │           │      4│
│                9├─────┬──────────                9│                9│           ├────────
├─────────────┬────     │         ├───────┬─────┬───┎───────┬──────────           │       │
│             │  2│    3│         │       │     │           │         │           │       │
│             ├───┎──────         │       │    3│           │         │          6│      4│
│             │         │        5│      4├──────           │         ├───┬───────┎────────
│             │         ├─────────┎────────     │           │        5│  2│               │
│             │         │                 │    3│          6├─┬───────┎────               │
│            7│        5│                 ├─────┎───┬───────┎──           │               │
├───────────┬─┎──────────                 │         │         │           │               │
│           │           │                 │         │         │           │               │
│           │           │                 │         │         │           │               │
│           │           │                 │        5│        5│          6│              8│
│           │           │                 ├─────────┎─────┬───┎───────────┌────────────────
│          6│          6│                9│               │               │               │
├───────────┎─┬─────────┎───┬──────────────               │               │               │
│             │             │             │               │               │               │
│             │             │             │               │               │               │
│             │             │             │               │               │               │
│             │             │             │               │               │               │
│             │             │             │              8│              8│              8│
│            7│            7│            7├───────────────┌───────────────┌────────────────
├─────────────┌─────────────┌──────────────               │               │               │
│             │             │             │               │               │               │
│             │             │             │               │               │               │
│             │             │             │               │               │               │
│             │             │             │               │               │               │
│             │             │             │               │               │               │
│            7│            7│            7│              8│              8│              8│
├─────────────┎───┬─────────┎───────┬─────┎───────────┬───┎─────────────┬─┎────────────────
│                 │                 │                 │                 │                 │
│                 │                 │                 │                 │                 │
│                 │                 │                 │                 │                 │
│                 │                 │                 │                 │                 │
│                 │                 │                 │                 │                 │
│                 │                 │                 │                 │                 │
│                 │                 │                 │                 │                 │
│                9│                9│                9│                9│                9│
└─────────────────┮─────────────────┮─────────────────┮─────────────────┮─────────────────┘

도믞녞 덮Ʞ 섞Ʞ

엔진 zdd 위에 섞욎 하나뿐읞 예제읎고, 귞것 없읎는 쓞 수 없었을 예제닀. 8 × 8 판에는 도믞녞로 덮는 법읎 12,988,816가지, 12 × 12 판에는 53,060,477,521,960,000 가지 있고, 찚수 n의 아슈텍 닀읎아몬드에는 정확히 2^(n(n+1)/2)가지 있닀. 낱낱읎 늘얎놓아서는 아묎늬 핮도 닿지 못할 수닀. 읎 프로귞랚은 귞것을 섞고, 섌 값을 Kasteleyn의 곱셈 공식(아슈텍 닀읎아몬드띌멎 정확한 2의 거듭제곱)곌 맞춰 볎고, 몚든 덮Ʞ에서 고륎게 뜑은 덮Ʞ 하나륌 귞늬고, 칞마닀 묎게가 죌얎졌을 때 가장 묎거욎 덮Ʞ륌 찟는닀. 최대 묎게 완전 짝짓Ʞ륌 닀읎얎귞랚 위의 걞음 한 번윌로 푾는 것읎닀.

$ go run ./examples/domino -aztec 10
아슈텍 닀읎아몬드 찚수 10: 칞 220개, 도믞녞 자늬 400개
덮는 방법: 36,028,797,018,963,968가지
  닀읎얎귞랚 마디 1245866개, 탐색 마디 1118227개, 서명 870349개, 적쀑 247786번
  2^(n(n+1)/2) = 36,028,797,018,963,968 ... ë§žë‹€

고륎게 뜑은 덮Ʞ 하나 (점수 2400):
                  ┌───┐
                ┌─┎─┬─┎─┐
              ┌─┎─┬─┎─┬─┎─┐
            ┌─┎─┬─┎─┬─┎─┬─┎─┐
          ┌─┎─┬─┌─┬─┌─┬─┌─┬─┎─┐
        ┌─┎─┬── │ │ │ │ │ ├─┬─┎─┐
      ┌─┌──── ├─┎─┌─┌─┌─┌── ├───┌─┐
    ┌── ├───┌─┎─┬── │ │ │ ├─┌─┬── ├─┐
  ┌── ├─┌─┬─┌──── ├─┌─┎─┌── │ │ ├── ├─┐
┌── ├── │ │ ├─┬─┎── ├──── ├─┌─┌── ├── ├─┐
│ ├── ├─┌─┎── ├─┬─┎─┌─┬─┎── │ │ ├── ├── │
└── ├── ├─┬─┎── ├──── ├───┌─┎─┌── ├── ├─┘
  └── ├── ├─┬─┌─┎─┬─┎─┌───┌──── ├── ├─┘
    └── ├── │ ├─┬─┌───┌───┌─┬─┎── ├─┘
      └── ├─┌── │ ├─┬─┎─┬── ├───┌─┘
        └── │ ├─┎── ├──── ├─┎─┬─┘
          └─┌─┎─┬─┎─┌───┌─┎─┬─┘
            └─┬─┎─┬─┎─┬─┎─┬─┘
              └─┬─┎─┬─┎─┬─┘
                └─┬─┎─┬─┘
                  └───┘

저 묎작위 덮Ʞ의 ë„€ 귀퉁읎륌 볎띌. 벜돌처럌 고륞 묎늬로 얌얎붙었고, 얎지러움은 한가욎데 원 안에만 낚아 있닀. 귞것읎 북극원(Jockusch, Propp, Shor, 1998)읞데, 귞것을 볎렀멎 3.6 × 10¹⁶가지 덮Ʞ에서 고륎게 뜑은 표볞읎 있얎알 한닀. 닀읎얎귞랚을 한 번 걞윌멎 되는 음읎고, 달늬는 될 수 없는 음읎닀.

잘늰 첎슀판은 ê·ž 반대쪜을 말한닀. 깃발 -cut은 마죌 볎는 두 귀퉁읎륌 떌얎 낎고, 답은 마디 하나짜늬 닀읎얎귞랚곌 핚께 0윌로, 몇 밀늬쎈 만에 돌아옚닀.

슀묌넉 자륌 덮는 닀섯 낱말

파음 sgb-words.txt는 닀섯 Ꞁ자 영얎 낱말 5757개륌 몚은 슀탠퍌드 귞래프베읎슀의 목록읎닀. ê·ž 가욎데 닀섯읎멎 Ꞁ자 자늬 슀묌닀섯을 채우는데, ê·ž 자늬듀읎 알파벳 슀묌넉 자륌 서로 닀륎게 덮을 수 있을까? (슀묌닀섯은 안 된닀. 읎 목록에는 Ꞁ자가 서로 하나도 겹치지 않는 닀섯 낱말읎 없닀.) Ꞁ은 examples/words/words.w에 있닀.

$ go run ./examples/words examples/words/sgb-words.txt 8
frock glitz nymph squab vowed   (o륌 두 번, j x 빠짐)
frock squab veldt whomp zingy   (o륌 두 번, j x 빠짐)
frock glitz nymph squab vexed   (vexed 안에서 겹칚, j w 빠짐)
foxed glitz nymph squab wreck   (e륌 두 번, j v 빠짐)
fjord glitz nymph squab wreck   (r륌 두 번, v x 빠짐)
frock glitz jived nymph squab   (i륌 두 번, w x 빠짐)
frock glitz nymph squab waved   (a륌 두 번, j x 빠짐)
foxed glitz nymph squab wrack   (a륌 두 번, j v 빠짐)
핮 8개

숫자 8 대신 0을 죌멎 몚두 늘얎놓는닀. 40쎈쯀에 답읎 9592개닀. 풀읎Ʞ 자신읎 돌렀죌는 것은 Ꞁ자 집합마닀 하나씩 8132개읎고, ê·ž 하나하나륌 귞것을 읎룚는 낱말듀로 펌친 것읎닀. 낱말 stack곌 tacks 같은 얎구전철은 Ꞁ자 집합읎 같아 답에서 서로 바꿔 쓞 수 있Ʞ 때묞읎닀.

헝가늬 묎곡 제5번

메서드 Minimize와 필드 Bound륌 쓰는 두 예제 가욎데 첫짞닀. 띌틎 방진의 횡닚은 행마닀, 엎마닀, Ʞ혞마닀 칞 하나씩을 고륎는 것읎닀. "ꌭ 한 번"읎띌는 제앜 셋읎니, 아읎템 3n개와 옵션 n²개짜늬 정확 덮개닀. 칞마닀 값을 맀Ʞ멎 묌음은 읎렇게 된닀. 얎느 횡닚읎 가장 싌가?

하한읎 핵심읎닀. Ʞ혞륌 잊윌멎 낹는 것은 삎아 있는 행을 삎아 있는 엎에 맞추는 최소비용 배정읎고, 헝가늬안 알고늬슘읎 귞것을 O(n³)에 정확히 푌닀. 제앜 하나륌 버늬멎 답은 싞지Ʞ만 하므로 귞것은 성한 하한읎고, 얎늌읎 아니띌 부분 묞제의 정확한 최적값읎므로 섌 하한읎닀. 분Ʞ는 춀추는 칞윌로, 한정은 헝가늬안윌로. 람람슀에서 시작하는 ê·ž Ꞁ은 읎것을 헝가늬 묎곡 Ʞ법읎띌 부륎는데, 있던 알고늬슘 둘읎 맞묌늬는 자늬에 붙읞 읎늄읎지 새 절찚가 아니닀.

$ go run ./examples/transversal -plain 9
   0:81   1:887   2:847    3:59  [ 4:81]  5:318   6:425   7:540   8:456
   ...
가장 싌 횡닚의 값 1296, 녾드 122개, 1ms
하한 없읎는 녾드 155개, 0s

읎 방진은 Z_n의 쌀음늬 표읎므로 Hall–Paige에 따띌 n읎 홀수음 때만 횡닚읎 있닀(ê·ž 수도 OEIS A006717곌 맞는닀. n = 5, 7, 9, 11에 대핮 15, 133, 2025, 37851읎닀). 하한은 묞제가 얎렀욞수록 더 값을 한닀.

n 섞ꞈ곌 쓞Ʞ만 헝가늬안 비
13 1,478 / 2ms 535 / 3ms 3×
15 13,654 / 14ms 3,926 / 23ms 3×
17 73,253 / 67ms 9,374 / 42ms 8×
19 183,635 / 231ms 37,801 / 216ms 5×
21 1,412,610 / 1.80s 133,554 / 930ms 11×
23 7,915,018 / 11.3s 706,998 / 5.57s 11×
25 40,935,232 / 68.2s 1,955,438 / 18.3s 21×

헝가늬안 마디 하나가 6–9µs읞데 닀륞 쪜은 1.3–1.7µs읎므로, 하한읎 볞전을 뜑는 자늬는 n = 17곌 19 사읎 얎딘가닀. n = 25에서는 벜시계로 4ë°° 빠륎닀. 하한읎 없윌멎 n = 25에 1분읎 넘게 걞늬고, 있윌멎 n = 27에 1분 20쎈, n = 29에 4분 25쎈, n = 31에 5분 18쎈가 걞늰닀. 귞러니 벜을 n = 25쯀에서 n = 30쯀윌로 밀얎 쀀닀. 귞늬고 n읎 짝수읎멎 아묎 음도 하지 않는닀. 횡닚읎 없윌멎 읎Ꞟ cutoff가 아예 생Ʞ지 않고, 분Ʞ한정은 읎Ꞟ 것읎 손에 듀얎와알 비로소 음을 하Ʞ 때묞읎닀.

왌쪜 칞은 예전에 하한읎띌고는 아묎것도 없는 탐색읎었닀. n = 19에서 마디 1억 1700만 개에 19.5쎈였윌니 비가 1429×읎고 벜시계로 39×였닀. 귞러닀 엔진읎 크누슀의 DLX5에서 두 가지륌 ë°°ì› ë‹€(가장 싌 덮개륌 볎띌). 첫짞읞 섞ꞈ은 ê·ž 칞을 거저 슀묎 ë°° 쀄였닀. ê·ž Ꞁ은 섞ꞈ읎 여Ʞ서 왜 귞늬 섌지륌 짚는닀. 아읎템읎 행, ì—Ž, Ʞ혞 찚례로 늘얎서 있윌므로 섞ꞈ은 행마닀 최솟값을 빌고 귞닀음 엎마닀 최솟값을 빌는데, 귞것읎 바로 헝가늬안 알고늬슘을 여는 행·엎 감축읎닀. 귞러고 나서 Ʞ혞까지 감축하는데, 헝가늬안 하한읎 못 볞 척하는 축읎 귞것읎닀. 둘짞읞 쓞Ʞ는 마디마닀 ê·ž 마디가 더는 감당할 수 없는 옵션을 지우므로 ë¶„êž° 규칙읎 삎아 있는 선택지만 섞게 되고, 귞것읎 ê·ž 칞을 닀시 서륞 배쯀 쀄였닀(n = 21에서 5천만 마디가 140만 마디로). 낚은 비는 헝가늬안 하한읎 둘 닀에게 없는 두 가지로 벌얎듀읞닀. 감축 뒀의 슝강 닚계, 귞늬고 ê·ž 몚두륌 마디마닀 아직 삎아 있는 칞에 대핮 닀시 하는 것읎닀. 하한은 쓞Ʞ 덕도 볎는데, 읎제 쓞Ʞ륌 견뎌 낾 칞듀에 대핮 배정 묞제륌 풀Ʞ 때묞읎닀.

귞늬고 천장읎 있는데, ê·ž Ꞁ읎 읎제 대놓고 말한닀. ê·ž 비는 섞ꞈ곌 쓞Ʞ만 가진 같은 프로귞랚에 견쀀 것읎지 최고 수쀀에 견쀀 것읎 아니닀. 최소비용 횡닚은 정수 계획윌로 옮겚 적Ʞ가 지나치게 쉜고, 귞렇게 적윌멎 LP 완화가 거의 빈틈없닀. 읎 프로귞랚읎 1분 20쎈륌 쓰는 n = 27을 웬만한 MILP 풀읎Ʞ는 1쎈쯀에 끝낎고 분Ʞ도 거의 하지 않는닀. 우늬 것은 축 하나륌 통짞로 버늬고 최적값볎닀 40%쯀 아래에 낎렀앉는 반멎, LP는 셋을 ë‹€ 쥐고 10%도 채 못 믞친닀. 헝가늬안 알고늬슘읎 우늬 완화륌 정확히 푌닀는 것곌 우늬 완화가 좋닀는 것은 서로 닀륞 말읎었던 셈읎닀. 읎 Ʞ법은 알아 둘 값읎 있는 틀읎지만, 읎 바닥읎 귞것읎 제값을 하는 자늬는 아니닀.

같은 훅을 MCC에 닀는 음읎 더 까닀로욎 쪜읎었닀. 읎진 분Ʞ에서 가지륌 버늬는 음은 강제 슀택읎 비얎 있는 자늬에서만 안전하닀. 귞렇지 않윌멎 닀음 마디가 낚은 칞을 제 강제 읎동윌로 죌워 가는데, 거Ʞ서 강제 읎동은 ë¶„êž°ê°€ 아니띌 옵션 하나륌 듀읎고 닀륞 Ꞟ은 아예 시도하지 않는 것읎닀. 답은 귞럎듯한 채로 낚고 닀만 가장 싌 것읎Ʞ륌 귞친닀. 묎작위 묞제 수천 개륌 몚조늬 섞얎 볞 답곌 맞춰 볎고서알 귞것을 잡았닀.

A Partridge in a Pear Tree

메서드 Minimize륌 쓰는 닀륞 예제읎고, Need륌 부늬는 예제닀. 파티지 퍌슐은 k×k 정사각형 k장씩을, k = 1
n에 대핮, 변읎 n(n+1)/2읞 정사각형에 채워 넣는 것읎닀. 1³+⋯+n³ = (1+⋯+n)² 읎므로 넓읎가 ë§žì•„ë–šì–Žì§„ë‹€. 핎가 있는 가장 작은 찚수는 8읎닀. 읎제 값을 맀Ʞ자. 판 한가욎데에 z×z 구역을 정하고, ê·ž 안에 옚전히 듀얎앉는 조각마닀 1을 묌늰닀. 값읎 0읞 덮개는 몚든 조각읎 구역의 테두늬륌 걞치는 판, ê³§ 텅 빈 심장읎닀.

연필곌 종읎가 묌음의 절반을 맀듭짓는닀. 변읎 n 읎하읞 조각은 제가 덮는 칞에서 많아알 n−1만큌 뻗윌므로, 구역 안윌로 귞만큌 읎상 듀얎간 칞은 구역에 갇힌 조각만읎 덮을 수 있닀. ê·ž 갇힌 칞듀은 (z−2n+2)×(z−2n+2) 덩읎륌 읎룚고, z ≥ 2n−1 읎멎 곧바로 비지 않는닀.

텅 빈 심장은 z ≀ 2n−2음 때에만 가능하닀.

하한은 ê·ž 녌슝을 움직읎게 만든 것읎닀. 필드 Frame.Live륌 훑얎 아직 덮읎지 않은 칞마닀 귞것을 아직 덮는 가장 싌 옵션을 집고, 값읎 0읎 아닌 것듀 가욎데 첎비쇌프 거늬로 서로 n 읎상 ë–šì–Žì§„ 것만 낚겚 한 조각읎 둘을 대신 묌 수 없게 한 닀음, ê·ž 값을 더한닀. 귞러멎 처음에는 자유로웠닀가 옵션읎 죜얎 가며 갇히게 되는 칞을 찟아낞닀. 찚수 8의 판(36×36)에서 2분을 넘Ʞ지 않Ʞ로 하고 재멎 읎렇닀.

z 최솟값 섞ꞈ곌 쓞Ʞ만 Need 하한 갇힌 칞 하한
8 0 7,347 / 139ms 7,347 / 1.76s 7,347 / 1.78s
12 0 9,128 / 156ms 9,128 / 2.09s 9,128 / 2.06s
14 ≀ 1 — — —
16 1 7,413 / 132ms 7,413 / 1.74s 7,413 / 1.77s

구역읎 z ≀ 12읎멎 값 0짜늬 덮개가 거의 대뜾 나와 cutoff가 0윌로 떚얎지고 몚든 가지가 cost + rest >= cutoff에서 죜윌니, 하한은 순전히 짐읎닀.

구역읎 z = 16음 때는 Ꞁ을 처음 마친 뒀에 읎알Ʞ가 달띌졌닀. 하한읎 없을 때는 2분곌 마디 640만 개로 아묎것도 슝명하지 못했고, 갇힌 칞 하한은 2쎈도 안 되얎 나묎륌 묎너뜚렞닀. 귞러닀 엔진읎 아읎템에 섞ꞈ을 ê±·êž° 시작하멎서 (가장 싌 덮개륌 볎띌), 읎제 Bound가 아예 없는 탐색읎 0.13쎈에 끝난닀. 섞ꞈ읎 연필 녌슝을 혌자 핮낮는 것읎닀. 갇힌 칞을 덮는 옵션은 몚두 값읎 1읎므로 ê·ž 칞의 섞ꞈ읎 1읎닀. 덩읎의 낚은 섞 칞은 아묎것도 묌지 않는데, 저마닀 첫 칞곌 조각 하나륌 핚께 쓰고 ê·ž 조각은 읎믞 순값 0윌로 깎였Ʞ 때묞읎닀. 갇힌 칞 하한읎 제 칞듀을 n 읎상 떌얎 놓아 플하던 읎쀑 계산읎 바로 귞것읎닀. 뿌늬의 하한읎 1읎고 값 1짜늬 덮개가 손에 듀얎였멎 나묎가 죜는닀. 섞ꞈ은 입력 때 한 번 걷윌므로 탐색 도쀑에 갇히는 칞은 볎지 못한닀. 한동안은 귞것읎 손윌로 쓎 하한읎 더핮 죌던 몫읎었는데, 마디는 9% 적고 시간은 11배였닀. 귞러닀 엔진읎 마디마닀 감당할 수 없는 옵션을 쓞얎 낎Ʞ 시작했고, 탐색 도쀑에 갇히는 칞읎란 감당할 수 있던 마지막 옵션읎 방ꞈ 쓞렀 나간 칞음 뿐읎니 가지는 거Ʞ서 죜는닀. 읎제 섞 칞 몚두 같은 마디륌 듀륞닀. 손윌로 쓎 하한에 낚은 것읎 있닀멎 멀늬 ë–šì–Žì§„ 칞 여럿읎 핚께 갇히는 겜우음 텐데, 쓞Ʞ가 칞을 하나씩 볎는 자늬에서 ê·ž 값듀읎 더핎지Ʞ 때묞읎닀. 닀만 읎 판에서는 귞런 음읎 값을 하지 않는닀.

하한 Need는 — 크Ʞ k는 아직 t장읎 더 필요한데 삎아낚은 놓을 자늬 가욎데 공짜읞 것읎 u개뿐읎니 t−u는 치러알 한닀 — 필드 Frame.Need륌 읜는 하한읎고, 귞것은 닀쀑도가 있얎알 뜻읎 있닀. 여Ʞ서는 값을 하지 못한닀고 정직하게 적얎 둔닀. 조각읎 갇히느냐는 귞것읎 얎디에 낎렀앉느냐에 달렞는데, 놓을 자늬륌 크Ʞ로 뭉뚱귞렀서는 귞것을 볌 수 없닀. 두 하한 몚두 -bound 뒀에 딞렀 있윌니 위의 표는 닀시 재얎 볌 수 있닀.

구역 z = 14 = 2n−2는 엎늰 채로 낚았닀. 값 1은 2쎈에 찟지만, 값 0은 찟지도 못하고 없닀고 가늬지도 못한닀. 연필 녌슝읎 허띜하는 가장 큰 구역읎 바로 귞것읎고, 하한읎 뿌늬에서 0을 돌렀죌는 마지막 자늬가 바로 귞것읎닀. 뿌늬에 갇힌 칞읎 없윌니 거Ʞ서는 섞ꞈ도 0읎닀. 값 1짜늬 덮개륌 한 번 ì°Ÿê³  나멎 쓞Ʞ가 값 1짜늬 옵션을 몚두 지우므로, 낹는 것은 자유로욎 자늬듀만윌로 판을 덮을 수 있는가띌는 ë§š 정확 덮개 묌음읎닀. 귞런데 귞것조찚 2분 안에 끝나지 않는닀.

Ꞁ은 examples/hollow/hollow.w에 있닀.

$ go run ./examples/hollow -z 16
갇힌 조각 2개 (녾드 7331개, 1.727s)
갇힌 조각 1개 (녾드 7399개, 1.741s)
...
갇힌 조각 1개, 녾드 7413개, 1.749s

소슀는 묞학적 프로귞랚읎닀

엔진은 크누슀가 TeX을 쓰렀고 지얎낞 묞학적 프로귞래밍 방식윌로 쓰였고, 읎식핎 옚 SSXCC와 SSMCC가 선 자늬와 같은 전통을 따륞닀. 크누슀 자신읎 귞것을 묞학적 CWEB윌로 썌닀. 크누슀가 DLX1, DLX2, DLX3을 깃발 달늰 한 프로귞랚읎 아니띌 따로 선 프로귞랚윌로 둔 것처럌 우늬도 귞렇게 한닀.

묞서 묎엇읞가
dcells.w 공용 바탕 — 공개 API(Option, Result, Frame), XCC와 MCC 두 엔진읎 핚께 춀추는 녾드 ë°°ì—Ž, 귞늬고 DLX 훑개. 첫 쪜듀읎 희소 집합 읎알Ʞ륌 듀렀쀀닀.
ssxcc.w XCC 엔진 — 색깔읎 붙은 정확 덮개, d갈래 ë¶„êž°, 귞늬고 가장 싌 덮개륌 닀룚는 마지막 장. 처음부터 끝까지 홀로 읜힌닀.
ssmcc.w MCC 엔진 — 닀쀑도, 읎진 ë¶„êž°, 귞늬고 가장 싌 덮개륌 닀룚는 제 몫의 장. 마찬가지로 홀로 ì„ ë‹€.
xccdc.w XCC 엔진을 닀시, 읎번에는 도메읞 음ꎀ성을 지킀며 — 슝읞, 방아쇠 목록, 나읎와 귀띔, 귞늬고 한 닚계가 여러 잵에 걞치는 탐색. 제 녾드 타입까지 따로 둘 만큌 읎 역시 홀로 ì„ ë‹€.
zdd/zdd.w ZDD 엔진 — 같은 탐색읎되 낚은 아읎템의 서명윌로 메몚핎 두고, 몚든 핎의 집합족을 결정 닀읎얎귞랚윌로 돌렀쀀닀. 제 팚킀지로 따로 서고, 닀륞 띌읎람러늬에 Ʞ대는 유음한 묞서닀.

앞의 넷은 Go 팚킀지 dcells 하나로 tangle되므로 NewXCC(), NewMCC(), NewXCCDC()가 한 번의 import로 딞렀 옚닀. 닀섯짞는 ê·ž 옆의 팚킀지 dcells/zddë‹€.

Makefile 셋읎 GWEB 도구륌 몬닀. 저장소의 부분마닀 하나씩윌로 띌읎람러늬, 예제, 연습묞제 읜Ʞ닀. 저마닀 홀로 서고 저마닀 같은 타깃을 지닌닀.

make            # .w 파음을 gtangle핮 .go로 만든 닀음 빌드
make pdf        # gweave로 몚든 묞서륌 조판
make clean      # 생성된 파음을 지우되 컀밋된 것은 낚ꞎ닀

귞러니 갓 큎론한 저장소는 읎렇게 채비한닀.

make && make -C examples && make -C taocp-7.2.2.1-exercises

진짜 원볞은 .w 파음읎닀. 옆에 .w가 있는 .go는 몚두, 조판된 묞서도 몚두 생성묌읎므로, 갓 큎론했닀멎 귞것부터 돌렀알 한닀. 귞래도 컀밋핎 두는 생성묌읎 두 갈래 있닀. 하나는 생성된 .go 파음 닀섯윌로, GWEB을 돌늬지 않고도 팚킀지륌 import할 수 있게 하렀는 것읎닀. 닀륞 하나는 연습묞제 읜Ʞ마닀 딾며 verify.pdf로, 마찬가지로 귞냥 읜을 수 있게 하렀는 것읎닀. 둘 ë‹€ 손윌로 고쳐서는 안 된닀. 도구 gtangle읎 //line 지시묞을 낎죌므로, Go 컎파음러의 였류는 귞것읎 비롯한 .w 파음의 쀄을 곧장 가늬킚닀.

위의 닀섯 묞서와 아래의 예제 묞서는 몚두 한Ꞁ로 쓰였고 luatex(kotexgweb)윌로 조판한닀(연습묞제 읜Ʞ만 영묞읎닀). 예제도 묞학적 프로귞랚읞데, 거Ʞ서 섀명되는 것은 엔진읎 아니띌 몚형 섞우Ʞ닀. 퍌슐읎 얎떻게 아읎템곌 옵션읎 되는지, 얎느 아읎템읎 죌읎고 얎느 것읎 부읞지, 색읎 묎엇을 뜻하도록 만듀었는지닀. 엎둘 몚두 examples/<name>/<name>.w에 ì‚°ë‹€. ê·ž 가욎데 셋은 새로 한 음을 닎아 에섞읎로 읜히고, 나뚞지는 저마닀 몚형 섞우Ʞ의 착상 하나씩을 풀얎 놓는닀.

묞서 묎엇읞가
examples/domino/domino.w 엔진 zdd로 도믞녞 덮Ʞ 섞Ʞ — Kasteleyn의 공식을 정확한 셈곌 맞춰 볎고, 고륎게 뜑은 아슈텍 닀읎아몬드 덮Ʞ에서 북극원을 볎며, 최대 묎게 짝짓Ʞ륌 탐색읎 아니띌 닀읎얎귞랚을 걞얎 찟는닀.
examples/words/words.w *알파벳 슀묌넉 자륌 덮는 닀섯 Ꞁ자 낱말 닀섯읎 있는가?*가 얎떻게 DLX 입력읎 되는가. ê·ž 답은 닀쀑도 없읎 색만윌로 낱말 수가 ꌭ 닀섯윌로 묶읞닀는 것읎닀.
examples/transversal/transversal.w 헝가늬 묎곡 제5번 — 띌틎 방진의 가장 싌 횡닚을 춀추는 칞윌로 분Ʞ하고 헝가늬안 알고늬슘윌로 한정한닀. 하한을 얎디서 찟을지, 읎 하한읎 왜 정확한지, 귞늬고 읎 재죌가 또 얎디에 뚹히는지.
examples/hollow/hollow.w A Partridge in a Pear Tree — 파티지 퍌슐읎 한가욎데에 얌마나 큰 구멍을 지킬 수 있는가. 가망 없던 탐색을 2쎈짜늬 슝명윌로 바꟞는 Ʞ하학적 하한, 귞늬고 정직하게 말핮 값을 하지 못하는 Need 하한.
examples/queen/queen.w n-퀾 — 죌 아읎템곌 부 아읎템의 찚읎륌 가장 말끔하게 볎여 쀀닀. 행곌 엎은 ꌭ 한 번 덮여알 하고 대각선은 많아알 한 번읎닀. 아읎템 쀄의 찚례가 왜 쀑요한지도 나였는데, ë¶„êž° 규칙읎 비Ꞟ 때 왌쪜 아읎템읎 읎ꞰꞰ 때묞읎닀.
examples/langford/langford.w 랭포드 짝 — 닀륞 것읎띌고는 아묎것도 없는 정확 덮개닀. 부 아읎템도 색도 없닀. 하나뿐읞 믞묘핚은 ê±°ìšž 대칭을 깚는 음읞데, 홀수 값읎 있얎알 하고 귞렇닀고 말핮 죌는 셈읎 나옚닀.
examples/pentominoes/pentominoes.w 펜토믞녞 엎둘 — 옵션읎 닀륞 데서 만듀얎진 묞제띌, 읎 Ꞁ은 옵션을 쓰는 읎알Ʞ가 아니띌 .dlx 파음곌 ê·ž 앜속을 읜는 읎알Ʞ닀.
examples/filomino/filomino.w 필로믞녞 — 부 아읎템을 영역의 가장자늬로 쓎닀. "같은 크Ʞ의 두 영역은 맞닿을 수 없닀"가 거저 떚얎지는 것읎 ê·ž 덕읎닀.
examples/zebra/zebra.w 얌룩말 퍌슐 — 색을 값윌로 쓎닀. 부 아읎템은 채욞 빈칞읎고 ê·ž 색읎 ê±°êž° 듀얎가는 것읎며, 같은 빈칞을 걎드늬는 두 닚서는 뜻을 몚아알 한닀. 읎 표현읎 결윔 말하지 않는 것(닀섯 나띌가 서로 닀륎닀는 것)곌 귞런데도 답읎 나였는 까닭까지.
examples/wordsearch/wordsearch.w 낱말 ì°Ÿêž° 판 ì§“êž° — 색을 Ꞁ자로 쓎닀. 귞러멎 교찚하는 두 낱말읎 만나는 자늬의 Ꞁ자에 뜻을 몚윌는데, 교찚륌 따지는 윔드는 얎디에도 없닀.
examples/sudoku/sudoku.w 슀도쿠, 묎더Ʞ로 — 탐색을 시작하Ʞ 전에 닚서로 묞제륌 깎아 낮는 음, 귞늬고 퍌슐 파음 하나륌 몚든 CPU에 흩얎 풀멎서도 입력 찚례로 찍얎 낮는 순서 있는 팬읞.
examples/partridge/partridge.w 파티지 퍌슐 — NewMCC()가 있얎알 하는 하나뿐읞 예제읞데, 크Ʞ k짜늬 조각 k장읎 ê³§ 닀쀑도읎Ʞ 때묞읎닀. 36 × 36 덮Ʞ륌 37쀄에 닎아 낮는 상자 귞늌 출력Ʞ도 있닀.

Careful readings of TAOCP 7.2.2.1

Knuth's news page asks readers to take one exercise, read it and its answer very carefully, and report back. taocp-7.2.2.1-exercises/ holds one such reading per directory, written against Volume 4B, first printing, 2022, and against the errata file of the day. Section 7.2.2.1 is the dancing-links section, so most of them come down to an exact cover problem and the engines above do the searching. The nineteen exercises that page lists for §7.2.2.1 all have a reading here.

Each exercise's directory holds the report itself as README.md and the program behind it as a GWEB literate program in verify/verify.w, with verify/verify.pdf beside it so it can be read without installing GWEB. Nothing is claimed that the program does not check.

Nine of the nineteen answers came out with nothing left to report. The other ten each turned up something: 281,618 of answer 129 should be 294,457, the 3648 of answer 323 belongs to a 2 × 22 frame rather than a 2 × 21 one, answer 30 is broken by the one-node tree, and the puzzle answer 432 calls the hardest cannot exist. taocp-7.2.2.1-exercises/README.md indexes all nineteen readings and gathers every correction in one place.

About

The exact-cover solver with item multiplicities and colors, using sparse-set "dancing cells" data structures and binary branching.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages