changeset 8:809f7d058647

Some more dp problems
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 19 Feb 2023 15:17:09 +0100
parents 1ecfe01af17e
children 33a23228ef5c
files julia/longest_common_subsequence.jl python/dp.py
diffstat 2 files changed, 128 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/julia/longest_common_subsequence.jl	Sun Feb 19 12:50:51 2023 +0100
+++ b/julia/longest_common_subsequence.jl	Sun Feb 19 15:17:09 2023 +0100
@@ -1,3 +1,49 @@
+function lcss_len(x::Vector{T}, y::Vector{T}, i=1, j=1, a=nothing) where {T}
+    a = isnothing(a) ? zeros(T, min(length(x), length(y))) : a
+    if i > length(x) || j > length(y)
+        0
+    elseif x[i] == y[j]
+        n = 1 + lcss_len(x, y, i+1, j+1, a)
+        a[n] = x[i]
+        n
+    else
+        max(lcss_len(x, y, i+1, j, a), lcss_len(x, y, i, j+1, a))
+    end
+end
+
+function lcss_diff(x::Vector{T}, y::Vector{T}) where {T}
+    lcss = longest_common_subsequence(x, y)
+    i, j, k = 1, 1, 1
+    while i <= length(lcss) && j <= length(x) && k <= length(y)
+        if x[j] == lcss[i] && y[k] == lcss[i]
+            i += 1
+            j += 1
+            k += 1
+        elseif x[j] == lcss[i] && y[k] != lcss[i]
+            println("Added: $i $(y[k])")
+            k += 1
+        elseif y[k] == lcss[i] && x[j] != lcss[i]
+            println("Removed: $i $(x[j])")
+            j += 1
+        else
+            println("Changed: $(x[j]) -> $(y[k])")
+            j += 1
+            k += 1
+        end
+    end
+end
+
+function lrss_len(x::Vector{T}, i=1, j=1) where {T}
+    if max(i, j) > length(x)
+        0
+    elseif x[i] == x[j] && i != j
+        1 + lrss_len(x, i+1, j+1)
+    else
+        max(lrss_len(x, i+1, j), lrss_len(x, i, j+1))
+    end
+end
+
+# This has a bug: e.g. [1,2,3,4,5,6] vs [1,2,4,5,6]. Sequences need to have same length
 function longest_common_subsequence(x::Vector{T}, y::Vector{T})::Vector{T} where {T}
     m, n = length(x), length(y)
     C = zeros(Int, m+1, n+1)
--- a/python/dp.py	Sun Feb 19 12:50:51 2023 +0100
+++ b/python/dp.py	Sun Feb 19 15:17:09 2023 +0100
@@ -1,4 +1,4 @@
-
+import numpy as np
 from functools import cache
 
 
@@ -42,3 +42,84 @@
                 right = n - 2 - left
                 N += 1 + circle_chords(left) * circle_chords(right)
         return N
+
+def subset_sum(s, n, tot):
+    if tot == 0:
+        return True
+    if n < 0 or tot < 0:
+        return False
+
+    incl = subset_sum(s, n-1, tot-s[n])
+
+    if incl:
+        return True
+
+    excl = subset_sum(s, n-1, tot)
+    return excl
+
+def equal_partitions(s):
+    S = sum(s)
+    if len(s) == 0 or S % 2 == 1:
+        return False
+    return subset_sum(s, len(s)-1, S/2)
+
+def find_min_matrix_path(mat, i=0, j=0, mem=dict()):
+    # Find min-cost path from (0,0) to mat.shape - (1,1)
+    if (i+1, j+1) == mat.shape:
+        return mat[i, j]
+    if (i,j) in mem:
+        return mem[i,j]
+    if i < mat.shape[0]-1:
+        via_right = find_min_matrix_path(mat, i+1, j, mem)
+    else:
+        via_right = 1e6
+    if j < mat.shape[1]-1:
+        via_down = find_min_matrix_path(mat, i, j+1, mem)
+    else:
+        via_down = 1e6
+    if via_right < via_down:
+        mem[i,j] = mat[i,j] + via_right
+        return mem[i,j]
+    else:
+        mem[i,j] = mat[i,j] + via_down
+        return mem[i,j]
+
+
+def count_matrix_paths_with_cost(mat, cost, i=0, j=0):
+    # Dest. is implicitly bottom right corner
+
+    # Base case:
+    if (i+1,j+1) == mat.shape:
+        return cost == mat[i,j], [[(i,j)]]
+
+    if i < mat.shape[0]-1:
+        via_right, rp = count_matrix_paths_with_cost(mat, cost - mat[i,j], i+1, j)
+    else:
+        via_right, rp = 0, []
+    if j < mat.shape[1]-1:
+        via_down, dp = count_matrix_paths_with_cost(mat, cost - mat[i,j], i, j+1)
+    else:
+        via_down, dp = 0, []
+    paths = []
+    if via_down+via_right > 0:
+        paths = [[(i,j)] + p for p in rp+dp]
+    return (via_down + via_right, paths)
+
+def min_sum_partition(s, n, S1=0, S2=0):
+    if n < 0:
+        return S1, S2
+    s11, s21 = min_sum_partition(s, n-1, S1+s[n], S2)
+    s12, s22 = min_sum_partition(s, n-1, S1, S2+s[n])
+
+    if abs(s11-s21) < abs(s12-s22):
+        print(f"{s[n]} in S1")
+        return s11, s21
+    else:
+        print(f"{s[n]} in S2")
+        return s12, s22
+
+def rodcut(L, lengths, prices):
+    if L < min(lengths):
+        return 0
+    return max(p+rodcut(L-l, lengths, prices) for (l, p) in zip(lengths, prices) if L-l >= 0)
+