[Baekjoon] 11660. 구간 합 구하기
문제 설명
문제
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
예제 입력 2
2 4
1 2
3 4
1 1 1 1
1 2 1 2
2 1 2 1
2 2 2 2
예제 출력 2
1
2
3
4
출처
알고리즘 분류
문제 풀이
# Dynamic Programming
누적합을 이용하는 동적 계획법
문제입니다.
풀이 과정
누적합을 이용하는 문제입니다.
좀 더 쉬운 문제들에서는 ‘행 방향’ 누적합 만을 이용했다면, 이 문제에서는 2차원 리스트에서 ‘행 방향’과 ‘열 방향’ 누적합을 모두 이용해야 합니다.
예제 입력 1로 예시를 들어보겠습니다.
처음 입력을 받았을 때는 아래와 같습니다.
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
여기서 행 방향으로 누적합을 구하면 아래와 같습니다.
1 3 6 10
2 5 9 14
3 7 12 18
4 9 15 22
여기에 열 방향 누적합까지 구합니다.
1 3 6 10
3 8 15 24
6 15 27 42
10 24 42 64
그럼 위 상태에서 입력으로 2 2 3 4
가 들어왔다고 하겠습니다.
(3, 4) 위치에 있는 수 42
는 1행~3행, 1열~4열의 수를 전부 더한 값입니다. 여기서 1행의 값들과 1열의 값들은 제외해주어야 합니다.
따라서 1행 1열~4열의 누적합인 (1, 4) 위치의 수 10
과 1열 1행~3행의 누적합인 (3, 1) 위치의 6
을 빼줍니다.
빼주는 과정에서 (1, 1) 위치의 수 1
이 두번 빼지므로, 한 번 더해줍니다.
그러면 답을 구할 수 있고, 이로부터 아래와 같은 식을 도출할 수 있습니다.
result = matrix[i2][j2] - matrix[i2][j1-1] - matrix[i1-1][j2] + matrix[i1-1][j1-1]
전체 코드
전체 코드입니다.
실제 코드에서는 구현의 편의를 위해 각 행, 열의 맨 앞에 0 값으로 패딩해줍니다.
import sys
input = sys.stdin.readline
N, M = map(int, input().split())
matrix = [[0 for _ in range(N+1)] for _ in range(N+1)]
for i in range(1, N+1):
nums = list(map(int, input().split()))
for j in range(1, N+1):
matrix[i][j] = matrix[i][j-1] + nums[j-1]
print(*matrix, sep='\n')
for i in range(1, N+1):
for j in range(1, N+1):
matrix[i][j] += matrix[i-1][j]
print(*matrix, sep='\n')
for _ in range(M):
i1, j1, i2, j2 = map(int, input().split())
result = matrix[i2][j2] - matrix[i2][j1-1] - matrix[i1-1][j2] + matrix[i1-1][j1-1]
print(result)
배운 점
- 구간합 문제에서는 누적합을 계산하여 실제 값을 계산할 때는 인덱싱으로 1번의 단순 연산(for문 없이)만 하면 되도록 구현한다.
- 누적합을 이용할 때는 구현의 편의를 위해 각 행/열의 맨 앞에 0으로 패딩을 해준다.
Leave a comment