BOJ 21608 - 상어 초등학교

BOJ 21608 - 상어 초등학교

이번 문제는 구현할 기능이 세 가지나 있는 문제입니다.

문제에서 인접한 자리는 상하좌우로만 된다고 나와 있습니다.

이번에는 4개로 나누어서 문제를 풀어보겠습니다.

  1. 입력값 받기

  2. 비어있는 칸 중에서 좋아하는 사람이 가장 많이 인접한 칸 찾기

  3. 빈칸이 가장 많이 인접한 칸 찾기

  4. 점수 계산

1. 입력값 받기

우리는 N x N 배열도 필요하므로 모든 값이 0인 배열 arr을 만들어주고, 입력값을 받아주면 됩니다.

여기서 N*N줄을 입력받을 때, 학생의 번호와 좋아하는 학생들을 딕셔너리로 저장하면 편합니다.

2. 좋아하는 학생이 가장 많이 인접한 칸

빈칸에서 좋아하는 학생이 가장 많이 인접한 칸을 찾아주면 됩니다.

우리는 좋아하는 학생이 가장 많이 인접한 칸이 여러 개일 수도 있으므로 love라는 리스트를 하나 만들어서 [인접한 좋아하는 학생 수, 좌표를 넣어줄 큐] 형태로 저장을 해야 합니다.

그래서 위와 같이 collections.deque를 불러오고, 첫 번째 단계는 love라고 해서 초기값은 [ 0, deque() ]로 만들어줍니다.

그리고 이제 (0, 0)에서 (n-1, n-1)중에 빈칸만 확인해서 초깃값을 업데이트하면 됩니다.

예를 들어서 love = [ 2, deque([(0, 0), (1, 2)])] 로 되어 있으면 현재 좋아하는 사람이 가장 인접된 수는 2이고, 그 칸은 (0, 0)과 (1, 2)가 있다는 뜻입니다. 만약 (3, 4)에서 좋아하는 사람이 가장 인접된 수가 3명이 된다면 love = [ 3, deque([(3,4)])] 가 됩니다.

이번 문제에는 상하좌우가 필요하므로 dx, dy 를 만들어줍니다.

그리고 상하좌우 인접한 자리를 확인할 때, 배열의 범위가 넘어가지 않는지 확인해야 하므로 범위 내에 있으면 True, 아니면 False를 반환하는 check 함수를 만들어주면 됩니다.

이제 for문을 돌려서 빈칸에서 좋아하는 사람이 가장 많이 인접한 칸을 찾으면 됩니다.

주의할 점

본문 세 번째 조건에서는 자리가 여러 개라면 1순위는 행의 번호가 가장 작은 칸을, 2순위는 열의 번호가 가장 작은 칸을 선택해야 합니다.

그래서 이건 정렬을 해야 한다고 생각할 수 있겠지만, 아래와 같이 탐색하게 되면 정렬을 하지 않아도 무조건 행의 번호가 작은 순, 행의 번호가 같으면 열의 번호가 작은 순으로 정렬될 수 있다는 것을 알 수 있습니다.

위와 같은 코드처럼 빈칸(if arr[x][y] == 0)일 때, (x, y)를 (nx, ny)로 만들어서 범위 내에 있는지 확인 후에 좋아하는 학생들 목록에 arr[nx][ny]가 들어가는지 확인해주면 됩니다. 들어가 있으면 val += 1을 해주고, 아니면 그냥 넘어가면 됩니다.

그리고 이제 val이 love[0]과 같으면 큐에 좌표를 넣어주고, val > love[0]이면 love = [ val, deque([(좌표)])]로 새로 만들어주면 됩니다.

이렇게 해서 첫 번째 조건을 완료하였습니다.

이제 큐에 들어 있는 원소의 개수가 2개 이상이면 두 번째 조건으로 넘어가고, 1개이면 바로 자리를 배정하면 됩니다.

그런데 어차피 원소의 개수가 1개이면, 두 번째 조건을 돌려도 원소가 1개만 있으므로 저 값으로 결정하게 됩니다.

그래서 저는 if문 없이 그냥 코드를 추가하겠습니다.

원소의 개수가 1개일 때의 바로 자리를 배정해주는 조건문을 추가하고 싶은 분은 위 코드를 넣어주시면 됩니다.

3. 빈칸이 가장 많이 인접한 칸 찾기

이제 love[1]의 큐를 가지고 빈칸이 가장 많이 인접한 칸을 찾아주면 됩니다.

이번에는 blank라는 리스트에 값을 저장하는데, blank의 값은 [빈칸이 가장 많이 있는 개수, 좌표들을 저장할 리스트] 로 만들어주면 됩니다.

첫 번째 조건과는 다르게 큐가 아닌 리스트로 저장해주는 이유는 굳이 큐를 사용할 필요는 없기 때문입니다.

이번엔 큐에서 원소를 빼서 확인하므로 while문을 이용하여 blank에 값을 넣어주면 됩니다.

val의 값이 blank[0]과 같으면 blank[1]에 좌표를 추가해주고, val > blank[0]이면 blank = [val, [좌표]]로 수정해주면 됩니다.

이제 blank[1]에 있는 첫 번째 값은 무조건 본문 1, 2 조건을 만족하면서 행의 번호와 열의 번호가 가장 작은 좌표입니다.

그래서 blank[1]의 첫 번째 값 좌표에 t번째 학생의 번호인 student[t][0]을 저장하면 되겠습니다.

4. 점수 계산하기

이제 좌석을 다 배정했으면 점수를 더해주면 됩니다. 본문에 있는 점수 배점대로 score라는 배열을 만들어서 score = [0, 1, 10, 100, 1000]을 만들어주고, 인접하고 있는 좋아하는 학생 수대로 ans에 점수를 더해주면 됩니다.

그리고 ans를 출력하면 끝나게 됩니다.

다른 방법

조건 1과 조건 2를 합쳐서 만들 수도 있습니다.

Last updated