https://www.acmicpc.net/problem/21608
21608번: 상어 초등학교
상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호
www.acmicpc.net
Problem
- 상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호가 매겨져 있고, (r, c)는 r행 c열을 의미한다. 교실의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫 칸은 (N, N)이다.
- 선생님은 학생의 순서를 정했고, 각 학생이 좋아하는 학생 4명도 모두 조사했다. 이제 다음과 같은 규칙을 이용해 정해진 순서대로 학생의 자리를 정하려고 한다. 한 칸에는 학생 한 명의 자리만 있을 수 있고, |r1 - r2| + |c1 - c2| = 1을 만족하는 두 칸이 (r1, c1)과 (r2, c2)를 인접하다고 한다.
- 학생의 만족도의 총 합을 구해보자.
조건
- 비어있는 칸 중에서 좋아하는 학생이 인접한 칸에 가장 많은 칸으로 자리를 정한다.
- 1을 만족하는 칸이 여러 개이면, 인접한 칸 중에서 비어있는 칸이 가장 많은 칸으로 자리를 정한다.
- 2를 만족하는 칸도 여러 개인 경우에는 행의 번호가 가장 작은 칸으로, 그러한 칸도 여러 개이면 열의 번호가 가장 작은 칸으로 자리를 정한다.
- 학생의 만족도는 자리 배치가 모두 끝난 후에 구할 수 있다. 학생의 만족도를 구하려면 그 학생과 인접한 칸에 앉은 좋아하는 학생의 수를 구해야 한다. 그 값이 0이면 학생의 만족도는 0, 1이면 1, 2이면 10, 3이면 100, 4이면 1000이다.
SOL
생각보다 구현이 간단했던 문제이다.
1. 비어있는 칸 중에서 좋아하는 학생이 인접한 칸의 정보
2. 인접한 칸 중에서 비어있는 칸의 정보
3. 행 번호의 정보, 열 번호의 정보
1,2,3 의 정보가 모두 있다면, 위의 조건대로 구할 수 있다.
- 1을 기준 -> 2를 기준 -> 3을 기준으로 sorted해주면, 된다. (sorted는 내림차순이니까, 많은게 앞에 올려면, 1,2 정보는 음수를 취해줘야한다)
- 학생에 대한 정보는 , defaultdict(list)의 형태로, 입력받은 순서대로 dictionary에 등록하는 형식으로 해준다.
비어있는 칸 중에서, 좋아하는 학생이 인접한 칸의 정보
비어있는 칸을 기준으로, 주변 어떤 학생이 인접해있는지 , 빈칸은 몇개있는지 반환하는 함수를 작성한다.
인접해있는 학생 정보를 토대로, 좋아하는 학생이 몇명 있는지 확인 해준다.
def chk_seat(y,x):
near=[]
empty=0
for k in range(4):
ny=y+dy[k]
nx=x+dx[k]
if not (0<=ny<N and 0<=nx<N):
continue
if board[ny][nx]>0:
near.append(board[ny][nx])
else:
empty+=1
return near,empty
앉을 자리 정하기
위의 정보를 가지고, 앉을 자리를 정한다. 1,2,3,4 기준으로 sorting을 해준다. sorted를 할 때, lambda를 이용해서 custom sorting을 해주면 된다.
def find_seat(Lst):
Lst = sorted(Lst,key=lambda x:(x[0],x[1],x[2],x[3]))
friend,empty,y,x=Lst[0]
return y,x
전체코드
#상어 초등학교
import sys
from collections import defaultdict
input= sys.stdin.readline
N=int(input().rstrip())
student = defaultdict(list)
dx=[0,1,0,-1]
dy=[1,0,-1,0]
# 학생 수 입력
for _ in range(N*N):
temp = list(map(int, input().split()))
student[temp[0]] = temp[1:]
board=[[0 for _ in range(N)] for _ in range(N)]
# 주위 빈칸과, 인접해 있는 친구들를 담은 List 반환
def chk_seat(y,x):
near=[]
empty=0
for k in range(4):
ny=y+dy[k]
nx=x+dx[k]
if not (0<=ny<N and 0<=nx<N):
continue
if board[ny][nx]>0:
near.append(board[ny][nx])
else:
empty+=1
return near,empty
def find_seat(Lst):
Lst = sorted(Lst,key=lambda x:(x[0],x[1],x[2],x[3]))
friend,empty,y,x=Lst[0]
return y,x
for i in student.keys():
Like_cnt=0
#학생 한명에 대해서, 모든 칸을 다 조사해봐야한다.
#1.비어있는 칸 중에서, 주위에 좋아하는 학생이 가장 많은 칸을 선택
#2. 1을 만족하는게 여러개면, 비어있는 칸이 가장 많은 칸으로 자리를 정한다.
#3. 2를 만족하는 칸도 여러개인 경우, 행 번호가 작은 칸, 그 다음은 열 번호가 작은 칸을 기준으로 정한다.
Lst=[]
tmp=[]
for y in range(N):
for x in range(N):
if board[y][x]:
continue
near,empty=chk_seat(y,x)
for like in student[i]:
if like in near:
Like_cnt+=1
tmp.append(-Like_cnt)
tmp.append(-empty)
tmp.append(y)
tmp.append(x)
Lst.append(tmp)
tmp=[]
Like_cnt=0
y,x=find_seat(Lst)
board[y][x] = i
ans=0
score=[0,1,10,100,1000]
for i in range(N):
for j in range(N):
cnt=0
friend_Lst=chk_seat(i,j)[0]
for friend in friend_Lst:
if friend in student[board[i][j]]:
cnt+=1
ans+=score[cnt]
print(ans)
'알고리즘 문제(SOL)' 카테고리의 다른 글
[백준/7579/파이썬] 앱 (0) | 2022.02.28 |
---|---|
[백준/24542/파이썬] 튜터-튜티 관계의 수 (0) | 2022.02.27 |
[백준/11659/파이썬] 구간 합 구하기 4 (0) | 2022.02.27 |
[백준/1371/파이썬] 가장 많은 글자 (0) | 2022.02.26 |
[백준/9205/파이썬] 맥주 마시면서 걸어가기 (0) | 2022.02.26 |