예제 #1
0
// For every way to order the polygonal types, perform depth-first search,
// returning as soon as a solution is found.
func problem61() int {
	polys := allFourDigitPolygons()
	perms := tools.Permutations([]int{0, 1, 2, 3, 4, 5}, 6)
	for _, perm := range perms {
		// We will build up candidate solutions incrementally. The
		// starting nodes are therefore the members of polys[perm[0]].
		var frontier tools.Stack
		for _, p := range polys[perm[0]] {
			frontier.Push(Node{p})
		}
		for len(frontier) > 0 {
			n := frontier.Pop().(Node)
			z := len(n)
			if z == 6 && isAllCyclic(n) {
				return tools.Sum(n...)
			} else if z < 6 {
				// Note that perm[z] contains the next
				// polygonal type in this order.
				for _, y := range polys[perm[z]] {
					if isCyclic(n[z-1], y) {
						child := append(append(Node{}, n...), y)
						frontier.Push(child)
					}
				}
			}
		}
	}
	return -1 // Unreachable because there is a known solution.
}
예제 #2
0
func problem75() int {
	limit := 1500000

	// A mapping from values of L to the number of right-angles triangles
	// with the perimiter L.
	triangles := make(map[int]int)

	// Use a depth-first search to exhaust the search space, starting with
	// the first Pythagorean triple.
	var frontier tools.Stack
	frontier.Push(Triple{3, 4, 5})

	for len(frontier) > 0 {
		t := frontier.Pop().(Triple)
		L := tools.Sum(t...)
		if L > limit {
			continue
		}
		triangles[L]++

		// We're not only interested in 'primitive triples', but
		// multiples too
		a, b, c := t[0], t[1], t[2]
		for i := 2; ; i++ {
			multiple := Triple{i * a, i * b, i * c}
			if tools.Sum(multiple...) >= limit {
				break
			}
			triangles[tools.Sum(multiple...)]++
		}

		for _, child := range t.children() {
			frontier.Push(child)
		}
	}

	count := 0
	for _, val := range triangles {
		if val == 1 {
			count++
		}
	}
	return count
}
예제 #3
0
// We are going to use a concurrent depth-first search with a worker goroutine
// pool of 4. Each goroutine will search for a solution from a different
// starting prime. As soon as a solution is found, we return from the function.
// Otherwise, we wait for all starting primes to be checked, and return an
// error.
func problem60() (int, error) {
	// It's not clear how many primes to search through. Experimentation
	// suggests a limit of 9000 produces the correct answer: 26033. Note
	// our algorithm does not guarantee the solution is the smallest
	// possible, but as a matter of fact, it is. We could verify our
	// answer by raising the limit to 26033, searching exhaustively, and
	// observing that no smaller solutions are found.
	limit := 9000
	var primes []int
	for i := 0; i < limit; i++ {
		if tools.IsPrime(i) {
			primes = append(primes, i)
		}
	}

	c := newCache()
	ans := make(chan int)   // Used to send the answer.
	done := make(chan bool) // Used to signal that all worker goroutines are done.
	pchan := make(chan int) // Used to send worker goroutines a starting prime to search.
	var wg sync.WaitGroup

	// Woker goroutine pool of 4.
	for i := 0; i < 4; i++ {
		wg.Add(1)
		go func() {
			for {
				p, ok := <-pchan
				if !ok {
					wg.Done()
					return
				}

				// Perform depth-first search starting at the given prime.
				var frontier tools.Stack
				frontier.Push(Node{p})

				for len(frontier) != 0 {
					n := frontier.Pop().(Node)
					if len(n) == 5 {
						ans <- tools.Sum(n...)
					}
					for _, prime := range primes {
						child := append(append(*new(Node), n...), prime)
						if prime > tools.Max(n...) && c.allConcatToPrime(child) {
							frontier.Push(child)
						}
					}
				}
			}
		}()
	}

	go func() {
		for _, p := range primes {
			pchan <- p
		}
		close(pchan)
		wg.Wait()    // Wait for all workers to complete their search
		done <- true // before sending completion signal.
	}()

	for {
		select {
		case x := <-ans:
			return x, nil
		case <-done:
			return -1, fmt.Errorf("problem60: no solution found with limit %v", limit)
		}
	}
}