- 연속하는 수들의 최대 합 구하기
- 그리드(Grid)에서 경로 찾기
- LCS(Longest common subsequence) 문제
maxSum = -∞
for i = 0 to n-1
for j = i to n-1
// sum = num[i]부터 num[j]까지의 합
sum = 0
for k = i to j
sum += num[k]
if(maxSum < sum)
maxSum = sum
O(n^3)
maxSum = -∞
for i = 0 to n-1
sum = 0
for j = i to n-1
sum = sum + num[j]
if (maxSum < sum)
maxSum = sum
O(n^2)
1) 부분문제 : x0, x1, ..., xi에 대하여 xi에서 끝나는 연속하는 수들의 최대 합을 구하라. (재귀적인 해를 고안)
2) 부분문제 (최적)해의 목적함수 :
3) 주어진 문제의 (최적)해의 목적함수 : max{sum[i]} (0≤i≤n-1)
4) 부분문제 (최적)해의 목적함수에 대한 점화식(재귀식) (recurrence relation)
p[i] : x0, x1, ..., xi에 대하여 xi에서 끝나면서 합이 최대가 되는 연속하는 수들의 시작 위치
p[i] = p[i-1] (if sum[i-1] ≥ 0)
p[i] = i (otherwise)
//sum, num, p는 배열(리스트)
//sum은 합, num은 수, p는 시작 위치
sum[0] = num[0]
p[0] = 0
for i = 1 to n-1
if (sum[i-1] ≥ 0)
sum[i] = sum[i-1] + num[i]
p[i] = p[i-1]
else
sum[i] = num[i]
p[i] = i
return max(sum) // sum의 원소 중 최댓값 반환
-python code
def searchLinear(n):
sum = [0 for i in range(n)]
num = [4, -5, 7, -3, 6, -2, 9, -2, 4, -3, -2, 2, -3, -1, 2, 4]
p = [0 for i in range(n)]
for i in range(1, n):
if (sum[i-1] >= 0):
sum[i] = sum[i-1] + num[i]
p[i] = p[i-1]
else:
sum[i] = num[i]
p[i] = i
print(p)
print(sum)
return max(sum)
print(searchLinear(16))
O(n)
행 : 가로 줄, 열: 세로 줄
The input is an n(행) x m(열) grid, in which each cell has a positive cost C(i,j) associated with it.
The bottom row is row 1, the top row is row n.
From a cell (i,j) in one step you can reach cells
The goal is to find the least cost path from the bottom of the grid to the top, where the cost of a path is the sum of costs of cells used on that path. (지나는 셀들의 비용이 최소가 되는 경우 찾기)
Example 4 x 5 Grid
Base case
# matrix= [[0 for i in range(m)] for j in range(n)]
import copy
m, n = map(int, input().split())
C = []
for i in range(m):
C.append(list(map(int, input().split())))
print(C)
def grid(m, n, C):
A = [0 for i in range(n)]
for i in range(m-1, -1, -1):
temp = copy.deepcopy(A) # 꼭 deepcopy 해주기!
# 아래서 temp 값 변경될 때 A도 같은 주소 참조 중이라
# temp 변경시 함께 변경 될 수 있음!!
for j in range(n):
if j == 0 and j < n-1:
temp[j] = C[i][j] + min(A[j], A[j+1])
elif j == n-1:
temp[j] = C[i][j] + min(A[j-1], A[j])
else:
temp[j] = C[i][j] + min(A[j-1], A[j], A[j+1])
print("pre:", temp)
A = temp
# print("after:",A)
return min(A)
print(grid(m, n, C))
# 4 5
# 2 8 9 5 8
# 4 4 6 2 3
# 5 7 5 6 1
# 3 2 5 4 8
시간복잡도 : O(mn)
예시 그림 :
문자열 X = ABCBDAB
X의 부분 수열(or 서열) (subsequence)은 X에서 몇 개의 문자를 지워서 얻어진다.
ex :
LCS problem
두 개의 DNA 순서열(sequence)이 있을 때, 이 두 개가 얼마나 비슷한가를 자주 측정하는 일이 발생된다.
예를 들어 아래와 같이 X, Y가 존재한다면,
이 때 둘은 얼마나 유사한가를 측정할 때, 둘의 LCS(순서가 유지)를 구하여 이것이 길면 길수록 둘은 더 유사한 것이 된다. (두 문자열의 유사도 측정의 의미)
i = j = 1
while (i ≤ n and j ≤ m)
if(xi == yj)
i += 1 (X의 위치 이동)
j += 1 (Y의 위치 이동)
else
j += 1 (xi ≠ yj) (Y의 위치만 이동)
if (i > n)
X is a subsequence of Y (X는 Y의 부분서열이다.)
else
X is not a subsequence of Y (X는 Y의 부분서열이 아니다.)
수행시간 : O(n + m)
# import copy
x = "%"+input()
y = "%"+input()
print(x, y)
print(len(x), len(y))
def LCS(x, y):
C = [[0 for i in range(len(y))] for j in range(len(x))]
L = [0 for i in range(len(y))]
for i in range(len(x)):
# temp = copy.deepcopy(L)
for j in range(len(y)):
if i == 0 or j == 0:
C[i][j] = 0
elif x[i] == y[j]:
C[i][j] = C[i-1][j-1] + 1
else:
C[i][j] = max(C[i][j-1], C[i-1][j])
print(C)
return C[len(x)-1][len(y)-1]
print(LCS(x, y))
% B D C A B A
[[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1],
[0, 1, 1, 1, 1, 2, 2],
[0, 1, 1, 2, 2, 2, 2],
[0, 1, 1, 2, 2, 3, 3],
[0, 1, 2, 2, 2, 3, 3],
[0, 1, 2, 2, 3, 3, 4],
[0, 1, 2, 2, 3, 4, 4]]
# ABCBDAB
# BDCABA