예제 #1
0
func problem68() int {
	const start = 6 // Each line cannot sum to less than 6 (1+2+3)
	const end = 27  // or greater than 27 (8+9+10)

	// Use a depth-first search.
	var frontier tools.Stack
	var solutions [][]int

	// Populate the initial frontier.
	for N := start; N <= end; N++ {
		for i := 1; i <= 10; i++ {
			r := Ring{
				solution: []int{i},
				used:     make(map[int]bool),
				N:        N,
			}
			r.used[i] = true
			frontier.Push(r)
		}
	}

	for len(frontier) > 0 {
		r := frontier.Pop().(Ring)
		if len(r.solution) == 15 {
			// Each solution can be described uniquely starting from the
			// group of three with the numerically lowest external node and
			// working clockwise. So we need to filter for solutions where
			// a < min(d, f, h, j)
			s := r.solution
			if s[0] < tools.Min(s[3], s[6], s[9], s[12]) {
				solutions = append(solutions, s)
			}
		}
		for _, child := range successors(r) {
			frontier.Push(child)
		}
	}

	// Process solutions according to the problem spec.
	var strlen = 16
	var answers []int
	for _, sol := range solutions {
		var ss []string
		for _, x := range sol {
			ss = append(ss, strconv.Itoa(x))
		}
		s := strings.Join(ss, "")
		if len(s) == strlen {
			val, _ := strconv.Atoi(s)
			answers = append(answers, val)
		}
	}
	return tools.Max(answers...)
}
예제 #2
0
// Recursively find the maximum value of the root node plus the largest
// of its children, and so on, all the way to the base.
func maxRoute(tr Triangle) int {
	if val, ok := cache[k(tr)]; ok {
		return val
	}
	root := tr[0][0]
	if len(tr) == 1 {
		return root
	}
	a, b := children(tr)
	result := root + tools.Max(maxRoute(a), maxRoute(b))
	cache[k(tr)] = result
	return result
}
예제 #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)
		}
	}
}