| // run | |
| // Copyright 2024 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| func main() { | |
| err := run() | |
| if err != nil { | |
| panic(err) | |
| } | |
| } | |
| func run() error { | |
| methods := "AB" | |
| type node struct { | |
| tag string | |
| choices []string | |
| } | |
| all := []node{ | |
| {"000", permutations(methods)}, | |
| } | |
| next := 1 | |
| for len(all) > 0 { | |
| cur := all[0] | |
| k := copy(all, all[1:]) | |
| all = all[:k] | |
| if len(cur.choices) == 1 { | |
| continue | |
| } | |
| var bestM map[byte][]string | |
| bMax := len(cur.choices) + 1 | |
| bMin := -1 | |
| for sel := range selections(methods) { | |
| m := make(map[byte][]string) | |
| for _, order := range cur.choices { | |
| x := findFirstMatch(order, sel) | |
| m[x] = append(m[x], order) | |
| } | |
| min := len(cur.choices) + 1 | |
| max := -1 | |
| for _, v := range m { | |
| if len(v) < min { | |
| min = len(v) | |
| } | |
| if len(v) > max { | |
| max = len(v) | |
| } | |
| } | |
| if max < bMax || (max == bMax && min > bMin) { | |
| bestM = m | |
| bMin = min | |
| bMax = max | |
| } | |
| } | |
| if bMax == len(cur.choices) { | |
| continue | |
| } | |
| cc := Keys(bestM) | |
| for c := range cc { | |
| choices := bestM[c] | |
| next++ | |
| switch c { | |
| case 'A': | |
| case 'B': | |
| default: | |
| panic("unexpected selector type " + string(c)) | |
| } | |
| all = append(all, node{"", choices}) | |
| } | |
| } | |
| return nil | |
| } | |
| func permutations(s string) []string { | |
| if len(s) <= 1 { | |
| return []string{s} | |
| } | |
| var result []string | |
| for i, char := range s { | |
| rest := s[:i] + s[i+1:] | |
| for _, perm := range permutations(rest) { | |
| result = append(result, string(char)+perm) | |
| } | |
| } | |
| return result | |
| } | |
| type Seq[V any] func(yield func(V) bool) | |
| func selections(s string) Seq[string] { | |
| return func(yield func(string) bool) { | |
| for bits := 1; bits < 1<<len(s); bits++ { | |
| var choice string | |
| for j, char := range s { | |
| if bits&(1<<j) != 0 { | |
| choice += string(char) | |
| } | |
| } | |
| if !yield(choice) { | |
| break | |
| } | |
| } | |
| } | |
| } | |
| func findFirstMatch(order, sel string) byte { | |
| for _, c := range order { | |
| return byte(c) | |
| } | |
| return 0 | |
| } | |
| func Keys[Map ~map[K]V, K comparable, V any](m Map) Seq[K] { | |
| return func(yield func(K) bool) { | |
| for k := range m { | |
| if !yield(k) { | |
| return | |
| } | |
| } | |
| } | |
| } |