본문 바로가기
알고리즘 PS (백준)/🐍 Python (파이썬)

[백준 11660번] 누적 합 알고리즘 - 파이썬(python)

by 코딩하는 동현😎 2022. 10. 2.

구간 합 구하기 5 

 

문제

N×N개의 수가 N×N 크기의 표에 채워져 있다. (x1, y1)부터 (x2, y2)까지 합을 구하는 프로그램을 작성하시오. (x, y)는 x행 y열을 의미한다.

예를 들어, N = 4이고, 표가 아래와 같이 채워져 있는 경우를 살펴보자.

1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7

여기서 (2, 2)부터 (3, 4)까지 합을 구하면 3+4+5+4+5+6 = 27이고, (4, 4)부터 (4, 4)까지 합을 구하면 7이다.

표에 채워져 있는 수와 합을 구하는 연산이 주어졌을 때, 이를 처리하는 프로그램을 작성하시오.

입력

첫째 줄에 표의 크기 N과 합을 구해야 하는 횟수 M이 주어진다. (1 ≤ N ≤ 1024, 1 ≤ M ≤ 100,000) 둘째 줄부터 N개의 줄에는 표에 채워져 있는 수가 1행부터 차례대로 주어진다. 다음 M개의 줄에는 네 개의 정수 x1, y1, x2, y2 가 주어지며, (x1, y1)부터 (x2, y2)의 합을 구해 출력해야 한다. 표에 채워져 있는 수는 1,000보다 작거나 같은 자연수이다. (x1 ≤ x2, y1 ≤ y2)

출력

총 M줄에 걸쳐 (x1, y1)부터 (x2, y2)까지 합을 구해 출력한다.


예제 입력 1

4 3
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
2 2 3 4
3 4 3 4
1 1 4 4

예제 출력 1

27
6
64

누적 합(Prefix Sum) / 구간 합

누적합 또는 구간 합 알고리즘은 코딩테스트에 사용 빈도가 높은 알고리즘이기 때문에 꼭 알아두면 좋습니다.

구간 합은 합 배열을 만들고, 재사용해서 시간 복잡도를 줄이는 알고리즘입니다.

고등학교 수1-수열에서 a1 ,a2...ai 가 수열의 일반항이고, S1,S2.....Sn가 수열의 합을 나타냈습니다.

똑같이 배열에서 A[0] + A[1] + .... A[n] 까지 더한것을 S[n]에 저장하고 불러오는 것입니다.

 

정의 : S[i] = A[0] + A[1] + .... A[i]

 

A[i] + ....+ A[j]  S[j] - S[i-1] 라는 간단한 연산으로 바로 구할 수 있습니다.

 

A[i] 부터 A[j]까지의 합을 합배열 없이 구하는 경우, 최악의 경우 0~N 인경우로 시간 복잡도는 O(N)입니다.

그러나 합 배열을 이용하면 O(1)안에 답을 구할 수 있습니다.

 

합 배열을 만드는 공식 : S[i] = S[i-1] + A[i]

 

입력에서 항을 하나씩 받을 때마다 기존의 합배열에 하나씩 추가하는 방법으로 진행 할수 있습니다.


이차원 구간 합?

하지만 문제에서는 일차원이 아니라 이차원 구간 합을 요구합니다.

그러면 입체적인 구간같은 경우에는 원점부터 (x,y)까지 직사각형의 합을 아래와 같이 일반항을 만들수 있습니다.

 

기존 배열

1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7

원점과 붙어있는 항들은 통상적인 합배열 공식으로 구해줍니다.

1 3 6 10
3 ?    
6      
10      

여기서 물음표 구간은 위에 1,3 사각형과 왼쪽에 1,3사각형을 더하고 물음표 자리에 있던 기존배열의 값(A[2][2] = 3)을 더해준뒤,  

1 사각형이 중복으로 더했기 때문에 빼면 됩니다.

 즉, 공식이 D[i][j] = D[i-1][j] + D[i][j-1] - D[i-1][j-1] + A[i][j] 이렇게 됩니다.

이 합배열을 이용해서 직사각형 구간의 합을 구해주면 됩니다.


파이썬 코드

#누적합
import sys;
input = sys.stdin.readline

N , M = map(int , input().split())
num = [[0] * (N+1)]
D = [[0 for _ in range(N+1)] for _ in range(N+1)]
for i in range(N):
    num.append([0] + [int(x) for x in input().split()])
for i in range(1, N+1):
    for j in range(1 , N+1):
        D[i][j] = D[i-1][j] + D[i][j-1] - D[i-1][j-1] + num[i][j]
for i in range(M):
    x1,y1,x2,y2 = map(int , input().split())
    result = D[x2][y2] - D[x1-1][y2] - D[x2][y1-1]+ D[x1-1][y1-1]
    print(result)
반응형

댓글