...
1
2
3
4
32
33
40
41 package main
42
43 import (
44 "flag"
45 "fmt"
46 "runtime"
47 )
48
49 var n = flag.Int("n", 7, "count")
50 var nCPU = flag.Int("ncpu", 4, "number of cpus")
51
52 type Job struct {
53 start []int
54 n int
55 }
56
57 type Found struct {
58 who *Kucher
59 k int
60 }
61
62 type Kucher struct {
63 perm []int
64 temp []int
65 flip []int
66 in chan Job
67 }
68
69 func NewKucher(length int) *Kucher {
70 return &Kucher{
71 perm: make([]int, length),
72 temp: make([]int, length),
73 flip: make([]int, length),
74 in: make(chan Job),
75 }
76 }
77
78 func (k *Kucher) permute(n int) bool {
79 i := 0
80 for ; i < n-1 && k.flip[i] == 0; i++ {
81 t := k.perm[0]
82 j := 0
83 for ; j <= i; j++ {
84 k.perm[j] = k.perm[j+1]
85 }
86 k.perm[j] = t
87 }
88 k.flip[i]--
89 for i > 0 {
90 i--
91 k.flip[i] = i
92 }
93 return k.flip[n-1] >= 0
94 }
95
96 func (k *Kucher) count() int {
97 K := 0
98 copy(k.temp, k.perm)
99 for k.temp[0] != 0 {
100 m := k.temp[0]
101 for i := 0; i < m; i++ {
102 k.temp[i], k.temp[m] = k.temp[m], k.temp[i]
103 m--
104 }
105 K++
106 }
107 return K
108 }
109
110 func (k *Kucher) Run(foreman chan<- Found) {
111 for job := range k.in {
112 verbose := 30
113 copy(k.perm, job.start)
114 for i, v := range k.perm {
115 if v != i {
116 verbose = 0
117 }
118 k.flip[i] = i
119 }
120 K := 0
121 for {
122 if verbose > 0 {
123 for _, p := range k.perm {
124 fmt.Print(p + 1)
125 }
126 fmt.Println()
127 verbose--
128 }
129 count := k.count()
130 if count > K {
131 K = count
132 }
133 if !k.permute(job.n) {
134 break
135 }
136 }
137 foreman <- Found{k, K}
138 }
139 }
140
141 type Fanner struct {
142 jobind int
143 jobsdone int
144 k int
145 jobs []Job
146 workers []*Kucher
147 in chan Found
148 result chan int
149 }
150
151 func NewFanner(jobs []Job, workers []*Kucher) *Fanner {
152 return &Fanner{
153 jobs: jobs, workers: workers,
154 in: make(chan Found),
155 result: make(chan int),
156 }
157 }
158
159 func (f *Fanner) Run(N int) {
160 for msg := range f.in {
161 if msg.k > f.k {
162 f.k = msg.k
163 }
164 if msg.k >= 0 {
165 f.jobsdone++
166 }
167 if f.jobind < len(f.jobs) {
168 msg.who.in <- f.jobs[f.jobind]
169 f.jobind++
170 } else if f.jobsdone == len(f.jobs) {
171 f.result <- f.k
172 return
173 }
174 }
175 }
176
177 func swapped(a []int, i, j int) []int {
178 b := make([]int, len(a))
179 copy(b, a)
180 b[i], b[j] = a[j], a[i]
181 return b
182 }
183
184 func main() {
185 flag.Parse()
186 runtime.GOMAXPROCS(*nCPU)
187 N := *n
188 base := make([]int, N)
189 for i := range base {
190 base[i] = i
191 }
192
193 njobs := 1
194 if N > 8 {
195 njobs += (N*(N-1))/2 - 28
196 }
197 jobs := make([]Job, njobs)
198 jobsind := 0
199
200 firstN := N
201 if firstN > 8 {
202 firstN = 8
203 }
204 jobs[jobsind] = Job{base, firstN}
205 jobsind++
206 for i := N - 1; i >= 8; i-- {
207 for j := 0; j < i; j++ {
208 jobs[jobsind] = Job{swapped(base, i, j), i}
209 jobsind++
210 }
211 }
212
213 nworkers := *nCPU
214 if njobs < nworkers {
215 nworkers = njobs
216 }
217 workers := make([]*Kucher, nworkers)
218 foreman := NewFanner(jobs, workers)
219 go foreman.Run(N)
220 for i := range workers {
221 k := NewKucher(N)
222 workers[i] = k
223 go k.Run(foreman.in)
224 foreman.in <- Found{k, -1}
225 }
226 fmt.Printf("Pfannkuchen(%d) = %d\n", N, <-foreman.result)
227 }
228
View as plain text