안전지대 (enumerate)
[문제 설명]
다음 그림과 같이 지뢰가 있는 지역과 지뢰에 인접한
위, 아래, 좌, 우 대각선 칸을 모두 위험지역으로 분류합니다.
지뢰는 2차원 배열 board에 1로 표시되어 있고 board에는
지뢰가 매설 된 지역 1과, 지뢰가 없는 지역 0만 존재합니다.
지뢰가 매설된 지역의 지도 board가 매개변수로 주어질 때,
안전한 지역의 칸 수를 return하도록 solution 함수를 완성해주세요.
[제한사항]
- board는 n * n 배열입니다.
- 1 ≤ n ≤ 100
- 지뢰는 1로 표시되어 있습니다.
- board에는 지뢰가 있는 지역 1과 지뢰가 없는 지역 0만 존재합니다.
[입출력 예]
board | result |
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0]] | 16 |
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]] | 13 |
[[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]] | 0 |
[입출력 예 설명]
입출력 예 #1)
(3, 2)에 지뢰가 있으므로 지뢰가 있는 지역과 지뢰와 인접한
위, 아래, 좌, 우, 대각선 총 8칸은 위험지역입니다.
따라서 16을 return합니다.
입출력 예 #2)
(3, 2), (3, 3)에 지뢰가 있으므로 지뢰가 있는 지역과 지뢰와 인접한
위, 아래, 좌, 우, 대각선은 위험지역입니다.
따라서 위험지역을 제외한 칸 수 13을 return합니다.
입출력 예 #3)
모든 지역에 지뢰가 있으므로 안전지역은 없습니다.
따라서 0을 return합니다.
[나의 풀이]
import numpy as np
def solution(board):
# 1. board를 matrix로 만들기
a = np.array(board)
# 2. 지뢰가 있는 위치를 list로 만들기
list_i = []
list_j = []
n_0 = a.shape[0]
n_1 = a.shape[1]
for i in range(0, n_0):
for j in range(0, n_1):
if a[i][j] == 1:
list_i.append(i)
list_j.append(j)
# 3. 지뢰가 있는 곳의 좌,우,상,하,대각선에 1 넣기
for i, j in zip(list_i, list_j):
a[max(i-1, 0):min(i+2, n_0), max(j-1, 0):min(j+2, n_1)] = 1
# 4. 1의 개수 세기
count = np.count_nonzero(a == 1)
# 5. 0의 개수 세기
return a.shape[0]*a.shape[1] - count
[설명]
1. board를 matrix로 만들기
import numpy as np
board = [[1, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 0, 0, 0, 1]]
a = np.array(board)
print(a)
Out[1] :
[[1 0 0 0 1]
[0 1 0 0 0]
[0 0 0 0 0]
[0 0 0 0 0]
[1 0 0 0 1]]
2. 지뢰가 있는 위치를 list로 만들기
list_i = []
list_j = []
for i in range(0, a.shape[0]):
for j in range(0, a.shape[1]):
if a[i][j] == 1:
list_i.append(i)
list_j.append(j)
print(list_i)
print(list_j)
Out[2] :
list_i = [0, 0, 1, 4, 4]
list_j = [0, 4, 1, 0, 4]
> 지뢰가 있는 위치가 (0, 0), (0, 4), (1, 1), (4, 0), (4, 4)이므로
위의 위치를 (x, y)라 한다면
x 의 위치는 list_i에 y의 위치는 list_j에 담았다.
3. 지뢰가 있는 곳의 좌,우,상,하,대각선에 1 넣기
for i, j in zip(list_i, list_j):
a[max(i-1, 0):min(i+2, a.shape[0]), max(j-1, 0):min(j+2, a.shape[1])] = 1
print(a)
Out[3] :
[[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 0 0]
[1 1 0 1 1]
[1 1 0 1 1]]
[ max, min를 쓴 이유 ]
> 만약 지뢰가 (1, 1)에 있다면 a[ i -1 : i +2, j -1 : j +2 ] = 1을 이용해 1을 넣을 수 있다.
i = 1, j = 1 이므로 a[ 0 : 3 , 0 : 3 ] = 1 이다.
> 만약 지뢰가 (0, 0)에 있고 a[ i -1 : i +2, j -1 : j +2 ] = 1을 이용한다면
i = 0, j = 0 이므로 a[ -1 : 2 , -1 : 2 ] = 1 이 된다.
그러나 마이너스는 쓸 수 없으므로 최소값이 0이고, 최댓값이 행, 열의 길이가 될 것이다.
따라서 a[max(i-1, 0):min(i+2, a.shape[0]), max(j-1, 0):min(j+2, a.shape[1])] = 1
으로 나타내어야 한다.
4. 1의 개수 세기
count = np.count_nonzero(a == 1)
print(count)
Out[4] :
21
5. 0의 개수 세기
a.shape[0]*a.shape[1] - count
Out[5] :
4
[다른 사람 풀이]
def solution(board):
# 1. 행 or 열 길이
n = len(board)
# 2. 지뢰가 있는 위치 구하고 상,하,좌,우,대각선 위치도 찾기
danger = set()
for i, row in enumerate(board):
for j, x in enumerate(row):
if not x:
continue
danger.update((i+di, j+dj) for di in [-1,0,1] for dj in [-1, 0, 1])
# 3. 안전지대 개수 구하기
return n*n - sum(0 <= i < n and 0 <= j < n for i, j in danger)
[설명]
1. 행 or 열 길이
board = [[1, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 0, 0, 0, 1]]
n = len(board)
print(n)
Out[6] :
5
> 행과 열이 5이므로 5가 나왔다.
2. 지뢰가 있는 위치 구하고 상, 하, 좌, 우, 대각선 위치도 찾기
danger = set()
for i, row in enumerate(board):
for j, x in enumerate(row):
if not x:
continue
print([(i, j) ])
print([(i+di, j+dj) for di in [-1,0,1] for dj in [-1, 0, 1]])
danger.update((i+di, j+dj) for di in [-1,0,1] for dj in [-1, 0, 1])
print(danger)
print()
Out[7] :
[(0, 0)] # ( i , j ) 첫 번째 지뢰의 위치
[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)] # ( 0, 0) 을 기준으로 상, 하, 좌, 우, 대각선 위치
{(0, 1), (-1, -1), (0, 0), (-1, 1), (1, 1), (1, -1), (-1, 0), (1, 0), (0, -1)} # 위의 값을 set으로 바꿔서 중복값 제거
[(0, 4)] # ( i , j ) 두 번째 지뢰의 위치
[(-1, 3), (-1, 4), (-1, 5), (0, 3), (0, 4), (0, 5), (1, 3), (1, 4), (1, 5)] # ( 0, 4) 을 기준으로 상, 하, 좌, 우, 대각선 위치
{(0, 1), (1, 3), (0, 4), (-1, -1), (-1, 4), (0, 0), (1, 5), (-1, 1), (1, 1), (0, 3), (1, -1), (1, 4), (-1, 0), (-1, 3), (0, 5), (1, 0), (0, -1), (-1, 5)} # 첫 번째 list, 두 번째 list를 set으로 바꿔서 중복값 제거
[(1, 1)] # ( i , j ) 세 번째 지뢰의 위치
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
{(0, 2), (0, 5), (2, 2), (1, 0), (1, 3), (-1, -1), (-1, 4), (-1, 1), (0, -1), (0, 1), (1, 2), (0, 4), (2, 1), (1, 5), (-1, 0), (-1, 3), (0, 0), (1, 1), (0, 3), (2, 0), (1, -1), (1, 4), (-1, 5)}
[(4, 0)] # ( i , j ) 네 번째 지뢰의 위치
[(3, 3), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5), (5, 3), (5, 4), (5, 5)]
{(4, 0), (3, -1), (3, 4), (4, 3), (3, 1), (5, -1), (5, 4), (5, 1), (0, 2), (0, 5), (2, 2), (1, 0), (1, 3), (-1, -1), (-1, 4), (-1, 1), (3, 0), (4, 5), (3, 3), (5, 0), (5, 3), (0, -1), (0, 1), (1, 2), (0, 4), (2, 1), (1, 5), (-1, 0), (-1, 3), (4, -1), (4, 1), (3, 5), (4, 4), (5, 5), (0, 0), (1, 1), (0, 3), (2, 0), (1, -1), (1, 4), (-1, 5)}
[ enumerate 특징 ]
- enumerate : 열거하다
- 리스트가 있는 경우 순서와 리스트의 값을 전달
- 이 함수는 순서가 있는 자료형(list, set, tuple, dictionary, string)을 입력으로 받아
인덱스 값을 포함하는 enumerate 객체를 리턴함 - 보통 enumerate 함수는 for문과 함께 자주 사용 됨
for i, row in enumerate(board):
print()
print(i, ':', row)
for j, x in enumerate(row):
print(j, ':', x)
Out[8] :
0 : [1, 0, 0, 0, 1]
0 : 1
1 : 0
2 : 0
3 : 0
4 : 1
1 : [0, 1, 0, 0, 0]
0 : 0
1 : 1
2 : 0
3 : 0
4 : 0
2 : [0, 0, 0, 0, 0]
0 : 0
1 : 0
2 : 0
3 : 0
4 : 0
3 : [0, 0, 0, 0, 0]
0 : 0
1 : 0
2 : 0
3 : 0
4 : 0
4 : [1, 0, 0, 0, 1]
0 : 1
1 : 0
2 : 0
3 : 0
4 : 1
3. 안전지대 개수 구하기
n*n - sum(0 <= i < n and 0 <= j < n for i, j in danger)
Out[9] :
4
> (전체 원소의 개수 (행 * 열)) - (2번에서 찾은 위험지대의 개수)
= 안전지대의 개수