developer-ellen
인간 디버거의 로그 찍기
developer-ellen
전체 방문자
오늘
어제
  • 분류 전체보기 (217)
    • 회고록 (0)
    • 취뽀 및 커리어 여정의 Stack (2)
      • SSAFY 7기 (2)
    • 프로그래밍공부 (24)
      • c++ (0)
      • JAVA (3)
      • Spring (5)
      • design pattern (3)
      • BackDB (1)
      • Servlet&JSP (3)
      • Vue (4)
      • JPA (4)
      • Infra (1)
      • Linux (0)
    • AI (3)
      • papers (3)
      • trend (0)
    • 프로젝트진행 (0)
      • 데이터베이스 (0)
      • 서버개발 (0)
      • 인공지능 (0)
      • 하루정리 (0)
    • 포트폴리오 (0)
    • 알고리즘 (158)
      • 알고리즘문풀 (155)
      • 알고리즘공부 (3)
    • 통계공부 (15)
      • 시계열분석 (15)
      • 회귀분석 (0)
    • CS (14)
      • 컴퓨터네트워크 (4)
      • 운영체제 (8)
      • 데이터베이스 (2)
    • 주저리주저리 (0)
      • 필사 (0)
    • 취업관련정보 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 삼성코테파이썬풀이
  • c++디자인패턴
  • 시계열
  • 삼성코테자바꿀팁
  • 통계학
  • c++ 빌더 패턴
  • 삼성코테기출자바풀이
  • 삼성코테구현문제추천
  • SW역량테스트파이썬
  • BOJ파이썬풀이
  • SW역량테스트파이썬풀이
  • ARIMA모형
  • 삼성코테파이썬준비
  • 시계열분석
  • 삼성코테준비
  • MA모형
  • 백준파이썬풀이
  • 삼성코테기출
  • 삼성코테자바풀이
  • 운영체제인터럽트
  • 코테파이썬
  • Arima
  • 카카오코테java풀이
  • 데이터분석
  • AR모형
  • 통계분석
  • 삼성코테파이썬
  • 삼성코테구현풀이
  • 카카오코테
  • 삼성코테자바준비

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
developer-ellen

인간 디버거의 로그 찍기

알고리즘/알고리즘문풀

BOJ - 상어 중학교 21609번 (python)

2021. 10. 21. 19:48

❓ 문제 - 백준 상어 중학교 21609번 - python 풀이법

 

출처 

(https://www.acmicpc.net/problem/21609)

 

21609번: 상어 중학교

상어 중학교의 코딩 동아리에서 게임을 만들었다. 이 게임은 크기가 N×N인 격자에서 진행되고, 초기에 격자의 모든 칸에는 블록이 하나씩 들어있고, 블록은 검은색 블록, 무지개 블록, 일반 블록

www.acmicpc.net

 

 

📝 문제해결법

1. 이 문제는 구현+BFS으로 풀었다.

  • board에 격자판에 대한 정보를 담고, while문을 통해 오토 플레이를 반복한다.
  • visited 함수로 BFS를 돌릴 때 방문처리와 동시에 블록 그룹의 번호를 저장한다. 무지개 블록의 경우 어떤 일반 블록에도 같이 껴서 블록 그룹을 형성할 수 있으므로 visited 값을 기본 값이 0이 아닌 배열 형태로 바꾼다.
  • 격자의 모든 행과 열을 돌면서 일반 블록이면서 아직 방문하지 않은 곳은 BFS를 돌려서 블록 그룹의 사이즈와, 블록 그룹 안에 있는 무지개 블록의 갯수를 리턴 받는다. 만약 블록 그룹의 사이즈가 1이라면 그룹을 형성할 수 없고, 그룹을 형성했으면 block 리스트의 그룹의 크기, 무지개블록의 갯수, 블록 기준 행, 열, 블록 번호를 append한다.
  • BFS를 돌린 후, 블록 그룹이 형성된 게 하나라도 없으면 while문을 빠져나간다.
  • block그룹이 여러 개라면 블록 그룹의 크기 -> 무지개 블록의 갯수 -> 블록 기준의 행 -> 열 각각 높은 순서로 정렬한 후 첫번째 인덱스의 있는 블록 그룹을 선택한다.
  • 가장 큰 블록 그룹을 선택 했으면 블록의 갯수를 더하면서, 블록을 제거한다. 제거 시 -2값으로 변경한다. 
  • 또한 블록의 갯수 * 블록의 갯수를 점수에 더해준다.
  • 블록을 중력상태로 만들기 위해 행 n-2인덱스부터 위로 올라가면서 일반블록이거나 무지개 블록일때, 밑에 블록이 비어 있다면 fall() 함수를 통해 블록을 밑으로 이동할 수 있을만큼 옮긴다.
  • 그후 zip()함수를 사용해 격자판을 반시계방향으로 돌린다.
  • 다시 블록을 중력상태로 만들기 위해 행 n-2인덱스부터 위로 올라가면서 일반블록이거나 무지개 블록일때, 밑에 블록이 비어 있다면 fall() 함수를 통해 블록을 밑으로 이동할 수 있을만큼 옮긴다.

3. 문제 풀면서 느낀점

  • 무지개블록은 어떤 일반 블록에도 낄 수 있어 블록 그룹에 들어갈 수 있으므로 방문처리를 할 때 배열형태로 하는 방법을 기억하자
  • 블록 그룹의 기준 위치를 어렵게 구현했었는데, BFS를 돌릴 때 인덱스 접근을 0 ~ n-1, 0 ~ n-1 하므로 따로 기준위치 처리가 필요없이 블록그룹이 형성된 행,열 값을 기준위치로 삼으면 된다.
  • 시계방향을 돌릴 땐 list(map(list, zip(*board[::-1])), 반시계방향을 돌릴 땐 list(map(list, zip(*board)))[::-1] 이다.. 꼭 기억하자

 

 

💻 소스코드

from collections import deque

n, m = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(n)]

dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

def bfs(x, y, visited, b_num):
    q = deque()
    q.append((x, y))
    c = board[x][y]
    visited[x][y] = b_num
    size, r_n = 1, 0
    while q:
        x, y = q.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <= nx < n and 0 <= ny < n:
                if board[nx][ny] == c and visited[nx][ny] == 0:
                    size += 1
                    visited[nx][ny] = b_num
                    q.append((nx, ny))
                elif board[nx][ny] == 0 and not b_num in visited[nx][ny]:
                    size += 1
                    r_n += 1
                    visited[nx][ny].append(b_num)
                    q.append((nx, ny))
    return size, r_n

def fall(x, y):
    stop = False
    for i in range(x+1, n):
        nx = i
        if board[nx][y] != -2:
            stop = True
            break
    if stop:
        board[nx-1][y] = board[x][y]
    else:
        board[nx][y] = board[x][y]
    board[x][y] = -2



score = 0
while True:
    visited = [[0]*n for _ in range(n)]
    for i in range(n):
        for j in range(n):
            if board[i][j] == 0:
                visited[i][j] = []

    b_num, block = 1, []
    for i in range(n):
        for j in range(n):
            if board[i][j] > 0 and visited[i][j] == 0:
                size, r_n = bfs(i, j, visited, b_num)
                if size > 1:
                    block.append([size, r_n, i, j, b_num])
                b_num += 1
    if len(block) == 0:
        break

    block.sort(key=lambda x:(-x[0], -x[1], -x[2], -x[3]))
    count = 0
    for i in range(n):
        for j in range(n):
            if board[i][j] > 0 and visited[i][j] == block[0][4]:
                count += 1
                board[i][j] = -2
            elif board[i][j] == 0 and block[0][4] in visited[i][j]:
                count += 1
                board[i][j] = -2

    score += (count*count)
    for i in range(n-2, -1, -1):
        for j in range(n):
            if board[i][j] >= 0 and board[i+1][j] == -2:
                fall(i, j)

    board = list(map(list, zip(*board)))[::-1]

    for i in range(n-2, -1, -1):
        for j in range(n):
            if board[i][j] >= 0 and board[i+1][j] == -2:
                fall(i, j)


print(score)

'알고리즘 > 알고리즘문풀' 카테고리의 다른 글

SW Expert Academy - 줄기세포배양 (python)  (0) 2021.10.22
BOJ - 마법사 상어와 비바라기 21610번 (python)  (0) 2021.10.21
BOJ - 마법사 상어와 파이어스톰 20058번 (python)  (0) 2021.10.21
BOJ - 마법사 상어와 토네이도 20057번 (python)  (0) 2021.10.21
BOJ - 마법사 상어와 파이어볼 20056번 (python)  (0) 2021.10.20
    '알고리즘/알고리즘문풀' 카테고리의 다른 글
    • SW Expert Academy - 줄기세포배양 (python)
    • BOJ - 마법사 상어와 비바라기 21610번 (python)
    • BOJ - 마법사 상어와 파이어스톰 20058번 (python)
    • BOJ - 마법사 상어와 토네이도 20057번 (python)
    developer-ellen
    developer-ellen

    티스토리툴바