2-B-1, 2-B-2
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
module algo
|
||||
|
||||
go 1.26.3
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package algo
|
||||
|
||||
func DP(t1 []int, t2 []int, e1 []int, e2 []int) int {
|
||||
Len := len(t1)
|
||||
if len(t2) != Len || len(e1) != Len || len(e2) != Len {
|
||||
return -1
|
||||
}
|
||||
dp1 := make([]int, Len)
|
||||
dp2 := make([]int, Len)
|
||||
dp1[0], dp2[0] = t1[0], t2[0]
|
||||
|
||||
for i := 1; i < Len; i++ {
|
||||
dp1[i] = min(dp1[i-1], dp2[i-1]+e2[i-1]) + t1[i]
|
||||
dp2[i] = min(dp2[i-1], dp1[i-1]+e1[i-1]) + t2[i]
|
||||
}
|
||||
|
||||
return min(dp1[Len-1], dp2[Len-1])
|
||||
}
|
||||
|
||||
func Rec(t1 []int, t2 []int, e1 []int, e2 []int) int {
|
||||
Len := len(t1)
|
||||
if len(t2) != Len || len(e1) != Len || len(e2) != Len {
|
||||
return -1
|
||||
}
|
||||
|
||||
return min(rec(t1, t2, e1, e2))
|
||||
}
|
||||
|
||||
func rec(t1 []int, t2 []int, e1 []int, e2 []int) (int, int, int, int) {
|
||||
Len := len(t1)
|
||||
if Len == 1 {
|
||||
return t1[0], 0x3f3f3f3f3f3f3f3f, 0x3f3f3f3f3f3f3f3f, t2[0]
|
||||
}
|
||||
mid := Len / 2
|
||||
a11, a12, a21, a22 := rec(t1[:mid], t2[:mid], e1[:mid], e2[:mid])
|
||||
b11, b12, b21, b22 := rec(t1[mid:], t2[mid:], e1[mid:], e2[mid:])
|
||||
s1 := e1[mid-1]
|
||||
s2 := e2[mid-1]
|
||||
return min(a11+b11, a11+s1+b21, a12+s2+b11, a12+b21), min(a11+b12, a11+s1+b22, a12+s2+b12, a12+b22),
|
||||
min(a21+b11, a21+s1+b21, a22+b21, a22+s2+b11), min(a21+b12, a21+s1+b22, a22+b22, a22+s2+b12)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package algo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testCase struct {
|
||||
t1 []int
|
||||
t2 []int
|
||||
e1 []int
|
||||
e2 []int
|
||||
}
|
||||
|
||||
func randomCase(rng *rand.Rand, n int) testCase {
|
||||
tc := testCase{
|
||||
t1: make([]int, n),
|
||||
t2: make([]int, n),
|
||||
e1: make([]int, n),
|
||||
e2: make([]int, n),
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
tc.t1[i] = rng.Intn(1000)
|
||||
tc.t2[i] = rng.Intn(1000)
|
||||
tc.e1[i] = rng.Intn(1000)
|
||||
tc.e2[i] = rng.Intn(1000)
|
||||
}
|
||||
|
||||
return tc
|
||||
}
|
||||
|
||||
func TestRecAndDPMatchOnRandomData(t *testing.T) {
|
||||
rng := rand.New(rand.NewSource(1))
|
||||
const casesPerLen = 200
|
||||
|
||||
for n := 1; n <= 128; n++ {
|
||||
for caseIdx := 0; caseIdx < casesPerLen; caseIdx++ {
|
||||
tc := randomCase(rng, n)
|
||||
gotRec := Rec(tc.t1, tc.t2, tc.e1, tc.e2)
|
||||
gotDP := DP(tc.t1, tc.t2, tc.e1, tc.e2)
|
||||
if gotRec != gotDP {
|
||||
t.Fatalf("mismatch for len=%d case=%d: Rec=%d DP=%d t1=%v t2=%v e1=%v e2=%v",
|
||||
n, caseIdx, gotRec, gotDP, tc.t1, tc.t2, tc.e1, tc.e2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDP(b *testing.B) {
|
||||
benchmarkByLen(b, "DP", DP)
|
||||
}
|
||||
|
||||
func BenchmarkRec(b *testing.B) {
|
||||
benchmarkByLen(b, "Rec", Rec)
|
||||
}
|
||||
|
||||
func benchmarkByLen(b *testing.B, name string, fn func([]int, []int, []int, []int) int) {
|
||||
lengths := []int{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000}
|
||||
|
||||
for _, n := range lengths {
|
||||
n := n
|
||||
b.Run(fmt.Sprintf("%s/len=%d", name, n), func(b *testing.B) {
|
||||
rng := rand.New(rand.NewSource(int64(n)))
|
||||
tc := randomCase(rng, n)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = fn(tc.t1, tc.t2, tc.e1, tc.e2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module algo
|
||||
|
||||
go 1.26.3
|
||||
@@ -0,0 +1,52 @@
|
||||
package algo
|
||||
|
||||
func DP(arr []int) int {
|
||||
n := len(arr) - 1
|
||||
if n <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
const inf = int(^uint(0) >> 1)
|
||||
dp := make([][]int, n)
|
||||
for i := range dp {
|
||||
dp[i] = make([]int, n)
|
||||
}
|
||||
|
||||
for length := 2; length <= n; length++ {
|
||||
for l := 0; l+length-1 < n; l++ {
|
||||
r := l + length - 1
|
||||
dp[l][r] = inf
|
||||
for k := l; k < r; k++ {
|
||||
cost := dp[l][k] + dp[k+1][r] + arr[l]*arr[k+1]*arr[r+1]
|
||||
if cost < dp[l][r] {
|
||||
dp[l][r] = cost
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[0][n-1]
|
||||
}
|
||||
|
||||
func Greedy(arr []int) int {
|
||||
if len(arr) <= 2 {
|
||||
return 0
|
||||
}
|
||||
|
||||
dims := append([]int(nil), arr...)
|
||||
cost := 0
|
||||
|
||||
for len(dims) > 2 {
|
||||
best := 1
|
||||
for i := 2; i < len(dims)-1; i++ {
|
||||
if dims[i] > dims[best] {
|
||||
best = i
|
||||
}
|
||||
}
|
||||
|
||||
cost += dims[best-1] * dims[best] * dims[best+1]
|
||||
dims = append(dims[:best], dims[best+1:]...)
|
||||
}
|
||||
|
||||
return cost
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package algo
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDPKnownCase(t *testing.T) {
|
||||
arr := []int{30, 35, 15, 5, 10, 20, 25}
|
||||
want := 15125
|
||||
|
||||
if got := DP(arr); got != want {
|
||||
t.Fatalf("DP(%v) = %d, want %d", arr, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreedyRandomCompare(t *testing.T) {
|
||||
r := rand.New(rand.NewSource(1))
|
||||
|
||||
for tc := 0; tc < 500; tc++ {
|
||||
matrixCount := r.Intn(5) + 3
|
||||
arr := make([]int, matrixCount+1)
|
||||
for i := range arr {
|
||||
arr[i] = r.Intn(9) + 2
|
||||
}
|
||||
|
||||
greedy := Greedy(arr)
|
||||
dp := DP(arr)
|
||||
if greedy < dp {
|
||||
t.Fatalf("greedy beat dp unexpectedly: arr=%v greedy=%d dp=%d", arr, greedy, dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreedyIsNotAlwaysOptimal(t *testing.T) {
|
||||
r := rand.New(rand.NewSource(2))
|
||||
found := false
|
||||
|
||||
for tc := 0; tc < 500; tc++ {
|
||||
matrixCount := r.Intn(5) + 3
|
||||
arr := make([]int, matrixCount+1)
|
||||
for i := range arr {
|
||||
arr[i] = r.Intn(9) + 2
|
||||
}
|
||||
|
||||
greedy := Greedy(arr)
|
||||
dp := DP(arr)
|
||||
if dp < greedy {
|
||||
t.Logf("found counterexample: arr=%v greedy=%d dp=%d", arr, greedy, dp)
|
||||
found = true
|
||||
}
|
||||
|
||||
if dp > greedy {
|
||||
t.Fatalf("why greedy < dp???")
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatal("expected to find at least one case where dp < greedy")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user