본문 바로가기
취준! ✒/삼성

[코테준비] 삼성20. 코드트리: 꼬리잡기놀이 python & 삼성식 출력

by deepbluechip 2023. 10. 12.
728x90

꼬리잡기놀이 

풀이 노트

team_list 구성의 변천사

1. 각 team의 이동선포함 모든 좌표를 list에 담고, start와 end를 표시하려 했다.

  • 이는 공을 던질 때, 어느 플레이어가 공을 받는지, 아니면 못받는지 처리하기 힘들어서 X 

2. team_list에 team별 사람이 있는 곳 좌표만 담으려 했다. 

  • 사람이 한칸씩 움직이는 것을 처리하기가 힘들어서 X → (1) 이동선 다 넣기 & (2) "머리→꼬리"순서대로 list에 넣기 & (3) 총 사람수 저장하는 list생성 

3. 위에 방법대로 하니, 여전히 어떤 사람이 공을 맞는지 알기 어려워서 → map에 표시 ! 

  • 새로운 map을 만들어서 각 팀당 몇번째 사람인지 표시했다. 사람이 없는 곳은 0!  people_map

 

풀이노트 - 풀면서 바뀐 것들이 많다.

 

정답 코드 (코드트리용)💻

아래 삼성 제출 느낌으로 바꿔서 푼 코드도 있다. (테케를 loop으로 돌리기)

# 꼬리잡기놀이
import copy
import sys

input = sys.stdin.readline

# input ------------------------------
n, m, k = map(int, input().split())
ori_map = [list(map(int, input().split())) for _ in range(n)]
# prepare ------------------------------
dr = [1, -1, 0, 0]
dc = [0, 0, 1, -1]


def in_range(r, c):
    """
    해당 좌표(r,c)가 격자 안에 존재 하는지
    :return:  True / False
    """
    if 0 <= r < n and 0 <= c < n:
        return True
    else:
        return False


# [1] make team_index_map & team_list & headtail_list -------------
""" team 위치 표시, team 별 사람 순서 (r,c)"""
team_index_map = [[-1] * n for _ in range(n)]  # 각 위치에 team index 표시 (이동선 위치), team index는 은 0,1,2,3...m
people_map = [[0] * n for _ in range(n)] # 각 위치에 사람 번호 입력 (team은 index map에서)
team_list = [[] for _ in range(m)]  # team 별 머리부터 꼬리 순서로 모든 이동선표시, index
team_len  = [0]*m # 각 index마다 team의 길이 저장
visited = [[False] * n for _ in range(n)]


def dfs(r, c, length, index):
    """
    team index [map]에 표시, team에 사람들 머리부터 순서대로 index저장 [list]
    :param r: row 좌표
    :param c: column 좌표
    :param length: 지금 들어온 좌표까지의 길이
    :param index: 현재 team index
    :return:
    """
    global visited, team_index_map, team_list, team_len, people_map, people_end
    visited[r][c] = True
    team_index_map[r][c] = index
    team_list[index].append((r, c))
    for direction in range(4):
        newr, newc = r + dr[direction], c + dc[direction]
        if not in_range(newr, newc) or visited[newr][newc] or ori_map[newr][newc] == 0:
            continue # 아니면, 다음것 확인
        # (1) 안가봤고 (2) 범위 내, (3) 빈칸이 아니면 - 꼬리면 하나 더 처리하고, 아니면, dfs
        length += 1
        if ori_map[newr][newc] == 3: # 꼬리면, 길이 저장 (index가 아니라 길이.  3이면, 3로저장)
            team_len[index] = length
            people_map[newr][newc] = length
            people_end = True
        if not people_end:
            people_map[newr][newc] = length
        dfs(newr, newc,length, index)
        break  # 하나 찾았으면, 다른 길 가볼 필요 없음 (길은 하나)
    return


index = 0
for i in range(n):
    for j in range(n):
        if not visited[i][j] and ori_map[i][j] == 1:  # 들린 적 없고, head라면, team 탐색 시작
            # (1) visited, team_list, team_index_map update
            visited[i][j] = True
            team_list[index].append((i, j))
            team_index_map[i][j] = index
            length = 1
            people_map[i][j] = length
            people_end=False
            # (2) 이동 방향중에 2꼬리가 아닌 곳부터 시작해서 이동
            for direction in range(4):
                newr, newc = i + dr[direction], j + dc[direction]
                if in_range(newr, newc) and ori_map[newr][newc] == 2:
                    people_map[newr][newc] =2
                    dfs(newr, newc, length+1, index)
                    break
            # (3) dfs 끝나면, 다음 team 찾아서
            index += 1  # 한 탐색이 끝나면, index +1

# # preparing단계를 잘 했는지 확인 해보는 print문
# print(team_index_map)
# print(people_map)
# print(team_list)
# print(team_len)
# # def ------------------------------
def move_one(index):
    """
    팀원 한 칸씩 이동 - 아래 두개 업데이트
    [1] team_list
    [2] people_map
    :param team_index:
    :return:
    """
    global team_list, people_map
    # [1] team_list
    temp = copy.deepcopy(team_list[index])
    team_list[index] = [temp[-1]] + temp[:-1]
    # [2] people_map
    for i, (r,c)  in enumerate(team_list[index]):
        if i+1 <= team_len[index]:
            # 사람 범위 내에 있을 때는 숫자로
            people_map[r][c] =i+1
        else:
            people_map[r][c] = 0

def where_ball(round):
    """
    공이 어느 방향, 몇번째에서 오는지
    :param round: 몇번째 round
    :return: 방향 (0~3), 몇번째(0~n-1)
    """
    ith = round%n
    direction = (round//n)%4
    return direction, ith
def reverse_people(index):
    """
    [1] list 반대
    [2] map 반대 (list를 기반으로)
    :param index: 
    :return: 
    """
    global team_list, people_map
    # [1]
    temp = copy.deepcopy(team_list[index])
    length = team_len[index]
    team_list[index][:length] = reversed(temp[:length])
    team_list[index][length:] =reversed(temp[length:])

    # [2] people_map
    for i, (r,c)  in enumerate(team_list[index]):
        if i+1 <= length:
            # 사람 범위 내에 있을 때는 숫자로
            people_map[r][c] =i+1
        else:
            break

def ball_hit_try(ball_dir, ball_index):
    """
    공 던져서 맞으면, 처리
    :param ball_dir:
    :param ball_index:
    :param point:
    :return: point
    """
    if ball_dir==0:
        # 좌 -> 우 (최소 column)
        for j in range(n):
            if people_map[ball_index][j]>0:
                point = people_map[ball_index][j] * people_map[ball_index][j]
                index = team_index_map[ball_index][j]
                reverse_people(index)
                return point

    elif ball_dir==1:
        # 하 -> 상 (최대 row)
        for i in range(n-1,-1, -1):
            if people_map[i][ball_index]>0:
                point = people_map[i][ball_index] * people_map[i][ball_index]
                index = team_index_map[i][ball_index]
                reverse_people(index)

                return point
    elif ball_dir ==2:
        # 우 -> 좌 (최대 column)
        for j in range(n-1,-1,-1):
            if people_map[n-1-ball_index][j]>0:
                point = people_map[n-1-ball_index][j]* people_map[n-1-ball_index][j]
                index = team_index_map[n-1-ball_index][j]
                reverse_people(index)
                return point

    else:
        # 상 -> 하 (최소 row)
        for i in range(n):
            if people_map[i][n-1-ball_index]>0:
                point = people_map[i][n-1-ball_index] * people_map[i][n-1-ball_index]
                index = team_index_map[i][n-1-ball_index]
                reverse_people(index)
                return point
    return 0

# # main ------------------------------
point = 0
for round in range(k):
    # [1] 한칸 움직이기
    for team_index in range(m):
        move_one(team_index)
    # [2] 공 공격
    ball_dir, ball_index = where_ball(round)  # 공 어디서 던져질지
    point += ball_hit_try(ball_dir, ball_index)  # 공 던지기 - 맞으면, (1) 점수 + (2) 방향 바꾸기

print(point)

 

 

 

정답!

 

 


 

정답 코드 (삼성st)💻

SW expert 문제를 보니 아래처럼 테스트 케이스를 돌리며 출력해야했다. 그래서 그렇게 되게 하는 코드를 짜봤다. (삼성에 익숙해지고자)

삼성식 출력

# 꼬리잡기놀이
import copy
import sys

sys.stdin = open("./input.txt")
input = sys.stdin.readline


# prepare ------------------------------
dr = [1, -1, 0, 0]
dc = [0, 0, 1, -1]

# def -----------------------------------
def in_range(r, c):
    """
    해당 좌표(r,c)가 격자 안에 존재 하는지
    :return:  True / False
    """
    if 0 <= r < n and 0 <= c < n:
        return True
    else:
        return False

def dfs(r, c, length, index):
    """
    team index [map]에 표시, team에 사람들 머리부터 순서대로 index저장 [list]
    :param r: row 좌표
    :param c: column 좌표
    :param length: 지금 들어온 좌표까지의 길이
    :param index: 현재 team index
    :return:
    """
    global visited, team_index_map, team_list, team_len, people_map, people_end
    visited[r][c] = True
    team_index_map[r][c] = index
    team_list[index].append((r, c))
    for direction in range(4):
        newr, newc = r + dr[direction], c + dc[direction]
        if not in_range(newr, newc) or visited[newr][newc] or ori_map[newr][newc] == 0:
            continue # 아니면, 다음것 확인
        # (1) 안가봤고 (2) 범위 내, (3) 빈칸이 아니면 - 꼬리면 하나 더 처리하고, 아니면, dfs
        length += 1
        if ori_map[newr][newc] == 3: # 꼬리면, 길이 저장 (index가 아니라 길이.  3이면, 3로저장)
            team_len[index] = length
            people_map[newr][newc] = length
            people_end = True
        if not people_end:
            people_map[newr][newc] = length
        dfs(newr, newc,length, index)
        break  # 하나 찾았으면, 다른 길 가볼 필요 없음 (길은 하나)
    return
def dfs_cover():
    """ team 위치 표시, team 별 사람 순서 (r,c)"""
    global index, visited, team_index_map, team_list, people_map, people_end
    for i in range(n):
        for j in range(n):
            if not visited[i][j] and ori_map[i][j] == 1:  # 들린 적 없고, head라면, team 탐색 시작
                # (1) visited, team_list, team_index_map update
                visited[i][j] = True
                team_list[index].append((i, j))
                team_index_map[i][j] = index
                length = 1
                people_map[i][j] = length
                people_end=False
                # (2) 이동 방향중에 2꼬리가 아닌 곳부터 시작해서 이동
                for direction in range(4):
                    newr, newc = i + dr[direction], j + dc[direction]
                    if in_range(newr, newc) and ori_map[newr][newc] == 2:
                        people_map[newr][newc] =2
                        dfs(newr, newc, length+1, index)
                        break
                # (3) dfs 끝나면, 다음 team 찾아서
                index += 1  # 한 탐색이 끝나면, index +1
def move_one(index):
    """
    팀원 한 칸씩 이동 - 아래 두개 업데이트
    [1] team_list
    [2] people_map
    :param team_index:
    :return:
    """
    global team_list, people_map
    # [1] team_list
    temp = copy.deepcopy(team_list[index])
    team_list[index] = [temp[-1]] + temp[:-1]
    # [2] people_map
    for i, (r,c)  in enumerate(team_list[index]):
        if i+1 <= team_len[index]:
            # 사람 범위 내에 있을 때는 숫자로
            people_map[r][c] =i+1
        else:
            people_map[r][c] = 0

def where_ball(round):
    """
    공이 어느 방향, 몇번째에서 오는지
    :param round: 몇번째 round
    :return: 방향 (0~3), 몇번째(0~n-1)
    """
    ith = round%n
    direction = (round//n)%4
    return direction, ith
def reverse_people(index):
    """
    [1] list 반대
    [2] map 반대 (list를 기반으로)
    :param index:
    :return:
    """
    global team_list, people_map
    # [1]
    temp = copy.deepcopy(team_list[index])
    length = team_len[index]
    team_list[index][:length] = reversed(temp[:length])
    team_list[index][length:] =reversed(temp[length:])

    # [2] people_map
    for i, (r,c)  in enumerate(team_list[index]):
        if i+1 <= length:
            # 사람 범위 내에 있을 때는 숫자로
            people_map[r][c] =i+1
        else:
            break

def ball_hit_try(ball_dir, ball_index):
    """
    공 던져서 맞으면, 처리
    :param ball_dir:
    :param ball_index:
    :param point:
    :return: point
    """
    if ball_dir==0:
        # 좌 -> 우 (최소 column)
        for j in range(n):
            if people_map[ball_index][j]>0:
                point = people_map[ball_index][j] * people_map[ball_index][j]
                index = team_index_map[ball_index][j]
                reverse_people(index)
                return point

    elif ball_dir==1:
        # 하 -> 상 (최대 row)
        for i in range(n-1,-1, -1):
            if people_map[i][ball_index]>0:
                point = people_map[i][ball_index] * people_map[i][ball_index]
                index = team_index_map[i][ball_index]
                reverse_people(index)

                return point
    elif ball_dir ==2:
        # 우 -> 좌 (최대 column)
        for j in range(n-1,-1,-1):
            if people_map[n-1-ball_index][j]>0:
                point = people_map[n-1-ball_index][j]* people_map[n-1-ball_index][j]
                index = team_index_map[n-1-ball_index][j]
                reverse_people(index)
                return point

    else:
        # 상 -> 하 (최소 row)
        for i in range(n):
            if people_map[i][n-1-ball_index]>0:
                point = people_map[i][n-1-ball_index] * people_map[i][n-1-ball_index]
                index = team_index_map[i][n-1-ball_index]
                reverse_people(index)
                return point
    return 0

# main ---------------------------------------
num_questions = int(input())
for question in range(num_questions):
    # input ------------------------------
    n, m, k = map(int, input().split())
    ori_map = [list(map(int, input().split())) for _ in range(n)]
    # 초기화 ------------------------------
    team_index_map = [[-1] * n for _ in range(n)]  # 각 위치에 team index 표시 (이동선 위치), team index는 은 0,1,2,3...m
    people_map = [[0] * n for _ in range(n)]  # 각 위치에 사람 번호 입력 (team은 index map에서)
    team_list = [[] for _ in range(m)]  # team 별 머리부터 꼬리 순서로 모든 이동선표시, index
    team_len = [0] * m  # 각 index마다 team의 길이 저장
    visited = [[False] * n for _ in range(n)]
    index = 0
    # [1] make team_index_map & team_list & headtail_list -------------
    dfs_cover()
    # [2] Round 시작
    point = 0
    for round in range(k):
        # [2-1] 한칸 움직이기
        for team_index in range(m):
            move_one(team_index)
        # [2-2] 공 공격
        ball_dir, ball_index = where_ball(round)  # 공 어디서 던져질지
        point += ball_hit_try(ball_dir, ball_index)  # 공 던지기 - 맞으면, (1) 점수 + (2) 방향 바꾸기

    print(f'#{question+1} {point}')
728x90