0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

動的計画法の基本概念

分割と再利用

動的計画法では、問題を部分問題に分割し、部分問題の解を保存して再利用します。この再利用により、同じ計算を繰り返すことを防ぎ、効率的に解を求めます。

Goサンプルコード(フィボナッチ)

package main

import "fmt"

func fibonacci(n int) int {
	if n <= 1 {
		return n
	}
	return fibonacci(n-1) + fibonacci(n-2)
}

// 再帰しながら計算結果をメモしておく
func fibonacciMemo(n int, memo map[int]int) int {
	if n <= 1 {
		return n
	}
	if _, exists := memo[n]; !exists {
		memo[n] = fibonacciMemo(n-1, memo) + fibonacciMemo(n-2, memo)
	}
	return memo[n]
}

// 再帰はせず、ループで計算結果をメモしておく
func fibonacciDP(n int) int {
	if n <= 1 {
		return n
	}
	dp := make([]int, n+1)
	dp[0], dp[1] = 0, 1
	for i := 2; i <= n; i++ {
		dp[i] = dp[i-1] + dp[i-2]
	}
	return dp[n]
}

func main() {
	n := 10
	memo := make(map[int]int)
	fmt.Println("Fibonacci number:", fibonacci(n))
	fmt.Println("FibonacciMemo number:", fibonacciMemo(n, memo))
	fmt.Println("FibonacciDP number:", fibonacciDP(n))
}

フィボナッチで30まで数えるベンチマーク

goos: darwin
goarch: amd64
pkg: go-cs
cpu: Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz
BenchmarkFibonacci-4                 282           4153664 ns/op               0 B/op          0 allocs/op
BenchmarkFibonacciMemo-4          324370              3128 ns/op            2216 B/op          6 allocs/op
BenchmarkFibonacciDP-4          12091509             97.58 ns/op             256 B/op          1 allocs/op
PASS
ok      go-cs   4.393s

参考として再帰のイメージ

呼び出された関数はコールスタックに積まれていき、積まれている一番上のものから処理していく(LIFO)

fibonacciMemo(10)
  fibonacciMemo(9)
    fibonacciMemo(8)
      fibonacciMemo(7)
        fibonacciMemo(6)
          fibonacciMemo(5)
            fibonacciMemo(4)
              fibonacciMemo(3)
                fibonacciMemo(2)
                  fibonacciMemo(1) -> 1
                  fibonacciMemo(0) -> 0
                fibonacciMemo(2) -> 1
              fibonacciMemo(3) -> 2
            fibonacciMemo(4) -> 3
          fibonacciMemo(5) -> 5
        fibonacciMemo(6) -> 8
      fibonacciMemo(7) -> 13
    fibonacciMemo(8) -> 21
  fibonacciMemo(9) -> 34
fibonacciMemo(10) -> 55

Goサンプルコード(ナップサック問題)

重さと価値が与えられたアイテムのリストから、重さの制限内で価値の最大化を目指す問題

package main

import "fmt"

func knapsack(weights, values []int, capacity int) int {
    n := len(weights)
    dp := make([][]int, n+1)
    for i := range dp {
        dp[i] = make([]int, capacity+1)
    }

    for i := 1; i <= n; i++ {
        for w := 0; w <= capacity; w++ {
            if weights[i-1] <= w {
                dp[i][w] = max(dp[i-1][w], dp[i-1][w-weights[i-1]]+values[i-1])
            } else {
                dp[i][w] = dp[i-1][w]
            }
        }
    }
    return dp[n][capacity]
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func main() {
    weights := []int{2, 3, 4, 5}
    values := []int{3, 4, 5, 6}
    capacity := 5
    fmt.Println("Maximum value:", knapsack(weights, values, capacity))
}
Maximum value: 7

Goサンプルコード(最長共通部分列)

2つの文字列を比べて、同じ順番で出てくる文字をつなげていったら、どれが一番長くなるかを探すこと

package main

import "fmt"

func lcs(s1, s2 string) int {
    m, n := len(s1), len(s2)
    dp := make([][]int, m+1)
    for i := range dp {
        dp[i] = make([]int, n+1)
    }

    for i := 1; i <= m; i++ {
        for j := 1; j <= n; j++ {
            if s1[i-1] == s2[j-1] {
                dp[i][j] = dp[i-1][j-1] + 1
            } else {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
            }
        }
    }
    return dp[m][n]
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func main() {
    s1 := "AGGTAB"
    s2 := "GXTXAYB"
    fmt.Println("Length of LCS:", lcs(s1, s2))
}
Length of LCS: 4
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?