본문 바로가기

백준 (PYTHON)/Bronze

[PYTHON/Bronze V] 백준 2738번 행렬 덧셈

반응형

 

문제 링크

 


 

풀이

 

이중 배열 A, B를 선언해 두 행렬의 값을 더한다.

풀이 중, 파이썬의 리스트 처리에는 익숙하지 않았기 때문에 다소의 시행착오가 있었다. 과정 속에서 배운 개념들을 정리해보려 한다. 

 

 

1. 파이썬에서의 이중 배열 선언

 

1) A = [][]

결과: SyntaxError: invalid syntax

 

2) A = [N][M]

결과: IndexError: list index out of range

 

3) A = [[0] * M] * N

결과: N줄에 원소 M개씩 제대로 출력. 그러나 A[1][0] = 1처럼 인덱스에 접근해 데이터를 바꾸는 경우, 모든 줄의 0번 인덱스가 1로 변경되었다.

 

이 방법으로 배열을 선언하게 되면 같은 개체를 복사해 여러 번 출력할 뿐이라는 사실을 확인했다. 반복문을 통해 같은 문자를 여러 차례 출력하는 것과 다름 없는 셈으로, 이를 파이썬에서는 얕은 복사(Shallow Copy)라고 부른다. 

 

4) A = [[0 for i in range(M)] for j in range(N)]

리스트 선언 시 내부에 for문을 이용하는 방법. 이를 통해 이중 배열을 제대로 선언할 수 있었다. (코드 1에서 확인 가능)

 

 

2. 인덱스를 사용해 배열을 출력할 수 없었던 문제 (map 함수, map 객체)

 

print(A[1][0])와 같은 방법으로 배열의 데이터값을 출력하려 하는 경우, TypeError: 'map' object is not subscriptable라는 에러 메시지가 출력되었다. 이를 해결하기 위해 'map' object에 대해 알아보았으며, 결과적으로 map 함수의 리턴값에 대해 잘못 이해하고 있었다는 사실을 발견했다.

 

기존에 나는 map 함수가 요소들의 자료형을 변환하여 새로운 리스트를 생성해 반환하는 줄 알고 있었다. 그러나 map 함수를 사용해 input을 받을 경우, 별도의 형 변환이 없는 한 새로운 리스트가 아닌 새로운 'map 객체'를 생성한다는 것을 알게 되었다. 해당 map 객체는 인덱스를 통한 데이터로의 접근이 불가능할 뿐더러 객체를 출력하려 할 경우 <map object at 0x042A6538>등의 출력값만을 반환한다. 정상적인 배열 출력 역시 불가능하다. 예시는 아래와 같다.

 

a = map(int, input().split())
10 20
a
<map object at 0x042A6538>
a[1]
Traceback (most recent call last):
  File "<(파일명)>", line 1, in <(모듈)>
    a[1]
TypeError: 'map' object is not subscriptable
type(a)
<class 'map'>

 

map 객체를 list로 형 변환 시켜주자 행렬의 내용을 정상적으로 출력할 수 있었다. (코드 1에서 확인 가능)

 

 

3. sys.stdin.readline 함수

 

출력 오류의 원인을 찾던 중 또 다른 입력 함수인 sys.stdin.readline 함수에 대해 알게 되었다. 백준 문제를 풀던 중 input() 함수를 사용했더니, 실행 시간 초과로 오답 처리 되었으며 이를 sys.stdin.readline 함수로 해결했다는 글이 다수였다.

 

input() 함수는 다음의 두 가지 특징을 가진다.

  • 문자열 자료형의 파라미터를 받을 수 있다. 이를 프롬프트(prompt)라고 부르는데, 사용자에게 입력할 값이 코드에서 어떤 역할을 하는지 알려주는 역할을 한다. 
  • 입력값을 받은 후 개행 문자를 자동으로 제거한다.

 

반면 sys.stdin.readline() 함수는 다음의 두 가지 특징을 가진다.

  • 정수 자료형의 파라미터를 받을 수 있다. 이는 sys.stdin.readline() 함수를 통해 입력 받을 수 있는 바이트 수를 지정하는 역할을 한다. 
  • 입력값을 받은 후 개행 문자를 따로 제거하지 않는다.

 

단 한 번의 입력만이 필요한 경우, 각 함수의 특징은 함수의 전체 실행 시간에 크게 영향을 미치지 않는다. 그러나 수 차례 반복하여 입력을 받아야하는 경우, input() 함수가 반복 시마다 추가적으로 실행하는 위 두 가지의 기능이 sys.stdin.readline() 함수에 비해 상당한 시간을 잡아먹게 된다. 

 

본 블로그는 문제풀이 백업을 위해 개설 된 만큼, 실행 시간 초과를 피하기 위해서라도 앞으로는 sys.stdin.readline() 함수를 사용하기로 했다. (코드 2에서 확인 가능)

 

 

코드

 

1) 코드 1

 

N, M = map(int, input().split())

A = [[0 for i in range(M)] for j in range(N)]
B = [[0 for i in range(M)] for j in range(N)]

for i in range(0, N):
	A[i] = list(map(int, input().split())) 

for i in range(0, N):
	B[i] = list(map(int, input().split()))

for i in range(0, N):
	for j in range(0, M):
		A[i][j] += B[i][j]
		print(A[i][j], end = " ")
	print()

 

2) 코드 2 (sys.stdin.readline)

 

코드 1의 최상단에 두 줄만 추가해주면 input마다 입력을 수정하지 않고도 sys.stdin.readline을 사용할 수 있다. 

 

import sys # sys.stdin.readline 함수를 실행하기 위해서는 우선 sys를 import 해주어야 한다.
input = sys.stdin.readline # input 함수를 sys.stdin.readline 함수로 대체했다.

 

반응형