Computer Science 🔍/Algorithm

[Python] 누적합 - 백준 2167. 2차원 배열의 합

nowall 2025. 2. 7. 02:53

📝 문제 요약

🔗  https://www.acmicpc.net/problem/2167

 < 입력 >
N M
N행 M열의 배열 (N줄로 주어짐)
반복 횟수
반복 횟수 만큼의 i, j, x, y
 < 출력 >
반복 횟수 만큼의 구간합

📜 처음 낸 코드 - 시간 초과

N, M = map(int, input().split())
matrix = []
for _ in range(N):
	temp = list(map(int, input().split()))
	matrix.append(temp)

rep = int(input())
for _ in range(rep):
	i, j, x, y = map(int, input().split())
#	print(sum(matrix[i-1:x][j-1:y]))
	answer = 0
	for k in range(i-1, x):
		tmp = sum(matrix[k][j-1:y])
		answer += tmp
	print(answer)

리스트 슬라이싱, sum()으로 냅다 더하기.

 

🔧 문제점

시간 복잡도를 계산해보자.

N, M = map(int, input().split())	# O(1)
matrix = []					
for _ in range(N):
	temp = list(map(int, input().split()))
	matrix.append(temp)				# matrix 초기화 : O(NM)

rep = int(input())					# O(1)
for _ in range(rep):				
	i, j, x, y = map(int, input().split())
#	print(sum(matrix[i-1:x][j-1:y]))
	answer = 0
	for k in range(i-1, x):			# 최대 O(N)
		tmp = sum(matrix[k][j-1:y])  # 최대 O(M) (리스트 슬라이싱 합 계산)
		answer += tmp				# 해당 반복문 O(NM)
	print(answer)

👉 O(rep*NM)

 

입력값의 범위를 봤을 때, 

(1 ≤ N, M ≤ 300)이고 K(1 ≤ K ≤ 10,000)이다. (내 코드에선 K를 rep라고 했다)

 

내가 쓴 코드와 같은 방식을Brute Force라고 한다.

이 방법을 쓰면 가능한 모든 경우를 단순무식하게 하나씩 다 확인한다. 완전 탐색도 이렇게 부른다. 

Brute Force는 입력 크기가 작을 때에 ( N <= 1000이면 O(N^2)도 가능 ) 사용하면 구현이 간단해서 좋을 수 있다.

  cf. 위 괄호 속의 기준은 CPU의 연산 속도를 기준으로 한 경험적인 값이다.

       1초를 기준으로 약10^8(1억)개의 연산이 가능하다고 가정.

 

Brute Force를 최적화하기 위해서

우리가 아는 다양한 알고리즘(누적합, 슬라이딩 윈도우, 분할 정복, 동적 계획법(DP), 정렬, 해시맵 등)을 사용할 수 있다.

통과 코드

import sys

input = sys.stdin.readline
N, M = map(int, input().split())
matrix = [list(map(int, input().split())) for _ in range(N)]
p_sum = [ [0]*(M+1) for _ in range(N+1) ]
for k in range(1, N+1):
	for l in range(1, M+1):
		p_sum[k][l] = (
        	matrix[k-1][l-1] + 
            p_sum[k-1][l] + 
            p_sum[k][l-1] - 
            p_sum[k-1][l-1]
        )

rep = int(input())
for _ in range(rep):
	i, j, x, y = map(int, input().split())
	result = p_sum[x][y] - p_sum[i-1][y] - p_sum[x][j-1] + p_sum[i-1][j-1]
	print(result)

👉 O(NM) + O(rep)

 

코드를 찬찬히 읽으며 matrix와 p_sum의 그림을 그려 생각해보면 알 수 있다.

이해하니 명쾌하고 깔끔해서 참 좋았다.

 

matrix는 List comprehension으로 입력 받기

 

➡️ to be continued...

추천 문제 : 백준 11660번 구간 합 구하기 5, 프로그래머스 연속 부분 수열 합 구하기

슬라이딩 윈도우 알고리즘