[Dynamic Programming] Maximum Subarray & Floyd Warshall Alg

2024. 12. 9. 01:14·CS/Algorithm
728x90
반응형

Maximum Subarray

  • Find the consective subarray with maximum sum 합이 최대가 되는 연속되는 서브 배열을 찾아라
  • O(\(N^3\)) is easy : sub array의 갯수가 n*(n+1) / 2개가 존재한다.
  • O(\(N^2\)) is kind of easy : 연속인 subarray는 시작과 끝 점으로 존재함. 즉 \(_{n+1}\)C\(_2\)개의 subarray가 존재한다.
  • O(N)?
  • Do we allow subarray with zero elements?

만약 전부 양수 : 배열 전체 (자기 자신도 부분 집합이라고 생각한다)

 

O(\(N^2\))에서 보면, 

이전에 구해둔 배열의 합에서 다음 것만 더하면 됨 => i~j 까지 더하는 과정이 O(1)로 줄어들게 됨

 

이러한 방법은 사이즈가 0인 배열을 고려하지 않는다.

입력 배열이 모두 음수인 경우에 사이즈가 0인 배열이 가장 작다. (풀이는 같은데 답이 달라질 수 있음)

 

ex) 사이즈가 2개인 배열의 합에 + x를 하면 사이즈가 하나 늘어난 합이 됨

ex) 1개의 배열은 그러면 사이즈가 0인 배열에 + y를 하여 사이즈가 1인 sum이 y가 된다. 

 

size가 0인 것을 허용하지 않는 경우, 이런 경우 음수가 나온다면, 이를 0으로 바꾸면 사이즈가 0인 배열의 합과 같아진다.

 

Idea 1

Compute the maximum subarray ending at element i

i번째에서 끝나는 가장 큰 subarray를 알고 있다고 가정하자

      i i+1    

 

i 번째와 바로 앞 부분을 포함하는 두 칸이 maximum subarray임을 알고 있다.

i 번째를 기준으로, 1,3,4칸 보다 2칸이 가장 큰 값이라는 것이다.

 

즉, i를 기분으로 1,2,3,4칸이 있는 것에서 i+1 칸을 추가하는 것이다.

i+1을 마지막으로 보았을 때, 가장 maximum인 값은 총 3칸인, i-1, i, i+1이다. (i-1, i가 가장 크기 때문이다)

 

size가 1개 이상인 경우

A[1], A[2], ... A[n]이 온다고 치자

S[1] = A[1]

S[i] = max (S[i-1] + A[i], A[i])

 

size가 0개 이상인 경우

S[0] = 0

S[i] = max (S[i-1] + A[i], 0)

 

Idea 2

  • Compute 2 values for each i
    • Max subarray that contains element i
    • Max subarray that may not contain element i
  • size 1 이상만 허용

1. i 번째 칸을 포함하는 것 중에 가장 큰 것 (왼쪽에서부터)

2. i 번째 칸을 포함하지 않는 것 중에 가장 큰 것 (붙어있지 않을 수도 있고, 붙어있을 수도 있음)

두 개의 답이 같을 수도 있다.

 

1 은 idea 1의 아이디어와 같다. max(p,q) 

2는 max(s, max(p,q))

 

Idea 3

  • Use Prefix Sum

prefix sum : 앞 부분의 합

\(P_1 = A_1\) 

\(P_2 = A_1 + A_2\) 

... 

\(P_{i+1} = P_i + A_{i+1}\)

 

 

i 한칸 : \(P_i - P_{i-1}\) 

i 포함 두칸 : \(P_i - P_{i-2}\)

...

전체 : \(P_i - P_0\)

 

i 번째를 포함하는 가장 큰 값을 찾는 것이기 때문에

빼는 값이 가장 작으면 됨

 

즉, prefix sum의 minimum을 계산하면 된다. 

 


All-Pairs Shortest Path

모든 쌍에 대한 Shortest Path

  • Given a Weighted Graph
  • Find the Shortest Path between all possible Pairs of Nodes
  • One Option : Fun Dijkstra N times -> O(nmlogn) *O(m+nlogn) -> O(mn + n2logn)

지금 설명하려는 알고리즘은 O(\(N^3\))이다. 

왜 다익스트라를 사용하지 않는가? n이 엄청나게 크지 않은 한, 지금 설명하려는 알고리즘이 빠르다

 

Floyed Warshall Algorithm

Idea

  • (Nodes are Numbered from 1 to N) -> 노드 번호는 그냥 번호일 뿐이다. 그저 이름일 뿐
  • Find Shortest Path from (all possible) i to j going through only the nodes in {1,2,3, ... k}
  • Do the above by increasing k from 0 to N

k = 0일 때를 활용하여 k = 1일때를 계산.. 같은 방법으로 k = n일때까지 계산

결국 지나는 집합이 {1,2,3, ... n}이 될 때 정답이 될 것이다.

즉, {1,2,3 ... k}만 거치는 shortest path는 정답보다 크거나 같을 것이다.

 

  • D[k][i][j] will contain the desired shortest path length
  • Calculate D[k][i][j] from D[k-1][i][j]
  • Initial values will be in D[0][i][j] : 다이렉트 엣지

 

Shortest Path from i to j using nodes in {1,2, ... k}

  • May use node k
  • Or may not use node k
  • The shorter of the 2 is the answer

둘 다 계산해보면 둘 중 어떤 것이 답인지 알 수 있음 

즉, 배열의 "해"는 k를 사용하는 경우와 쓰지 않는 경우 중 작은 것이다

이미 가장 짧은 이전의 것을 알기 때문에 두가지를 모두 계산할 필요는 없다

 

k를 사용하지 않는 경우 D[k-1][i][j]

k를 사용하는 경우 D[k-1][i][k] + D[k-1][k][j]

 

Q)k가 두 번 나올 수 있는가?

A)불가능하다. k가 두번 나오면 shortest path가 아니기 때문에 가운데 도는 부분을 없애야한다.

 

만약 k = i라면? 자동으로 1,2 케이스가 같아진다.

1번 케이스의 경우 D[k-1][i][j] = D[k-1][k][j]

2번 케이스의 경우 D[k-1][i][k] + D[k-1][k][j] = 0 + D[k-1][k][j]

이기 때문에 알고리즘에서 자동으로 두 개가 같아짐을 확인할 수 있다.

 

int D[n+1][n+1][n+1];

int F(int W[n+1][n+1], int n){
    for(i = 1; i <= n; i++)
        for(j = 1; j <= n; j++)    
            D[0][i][j] = W[i][j];
    
    for(k = 1; k <= n; k++)
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
                D[k][i][j] = min(D[k-1][i][j], D[k-1][i][k] + D[k-1][k][j]);
}

 

3차원 배열을 사용하며 메모리를 너무 많이 사용하고 있다.

지금 k에서는 k-1만 가져다가 쓰기 때문에, 모든 것을 기억할 필요 없으므로, 2개의 2차원 배열만 사용할 수 있다.

 

int D[2][n+1][n+1];

int F(int W[n+1][n+1], int n){
    for(i = 1; i <= n; i++)
        for(j = 1; j <= n; j++)    
            D[0][i][j] = W[i][j];
    
    for(k = 1; k <= n; k++)
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
                D[k%2][i][j] = min(D[(k-1)%2][i][j], D[(k-1)%2][i][k] + D[(k-1)%2][k][j]);
}

 

2차원 메모리의 있는 값들을 그냥 업데이트 해도 괜찮음

그렇지만, 지금 사용하는 값이 업데이트 된 값인지 아닌지 보장이 없음

 

int D[n+1][n+1];

int F(int W[n+1][n+1], int n){
    for(i = 1; i <= n; i++)
        for(j = 1; j <= n; j++)    
            D[i][j] = W[i][j];
    
    for(k = 1; k <= n; k++)
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
                D[i][j] = min(D[i][j], D[i][k] + D[k][j])
}

업데이트 된 값이여도 괜찮음

왜냐하면 D[k][i][k] = D[k-1][i][k]가 항상 성립한다.

왜냐하면 k까지 사용하지만 i부터 k까지 계산이기 때문에 현재 path에는 어짜피 k가 나오지 않는다.

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'CS > Algorithm' 카테고리의 다른 글

[Dynamic Programming] 근사 문자열 매칭과 거리 함수 & LCS  (0) 2024.12.09
[Dynamic Programming] Working Days & Path Counting & Matrix Chain Multiplication  (0) 2024.12.09
[ Divide and Conquer ] Matrix Multiplication & Karatsuba Algorithm  (0) 2024.12.05
[ Divide and Conquer ] Farthest Point  (3) 2024.12.04
[ Divide and Conquer ] Convex Hull  (1) 2024.10.23
'CS/Algorithm' 카테고리의 다른 글
  • [Dynamic Programming] 근사 문자열 매칭과 거리 함수 & LCS
  • [Dynamic Programming] Working Days & Path Counting & Matrix Chain Multiplication
  • [ Divide and Conquer ] Matrix Multiplication & Karatsuba Algorithm
  • [ Divide and Conquer ] Farthest Point
min_zu
min_zu
  • min_zu
    민주제도
    min_zu
  • 전체
    오늘
    어제
    • ._. (176)
      • AI (2)
        • DeepLearning (2)
        • CS231n (0)
      • Web (2)
        • ReactJS (0)
      • CS (83)
        • OS (7)
        • Data Structure (23)
        • Computer Architecture (8)
        • Computer Network (20)
        • Algorithm (25)
      • Linux (3)
        • KaliLinux (0)
        • Docker (1)
      • Hacking (83)
        • Write Up (25)
        • Pwnable (13)
        • Reversing (2)
        • Cryptography (12)
        • Web Hacking (4)
        • Window (6)
        • Network (7)
        • Web3 (13)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    AI
    DataStructure
    OS
    Web
    Search
    Linux
    DeepLearning
    Graph
    WinAFL
    Mac
    Sort
    Tree
    ComputerArchitecture
    UTM
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
min_zu
[Dynamic Programming] Maximum Subarray & Floyd Warshall Alg
상단으로

티스토리툴바