Carnival7
Change Developer
Carnival7
전체 방문자
오늘
어제
  • 분류 전체보기
    • 자바의 정석
    • 프로그래밍 언어별 tools
      • 파이썬
      • 자바
    • 코딩 테스트
      • 백준 강의 기초편
      • 백준 강의 연습편
      • 백준 강의 문제편
      • 삼성 기출
      • 백준 - 일반
      • 카카오 기출
      • 프로그래머스 - 일반
      • 코테 풀이 Tools
    • CS
      • Network
      • 운영체제
      • 알고리즘
      • DB
    • Web_Backend
      • Spring
      • 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
      • 스프링 핵심 원리 - 기본편
    • DevOps
    • IT 업무 지식
      • 인프라
      • 클라우드
    • 자격증
      • AWS - CLF
      • 정처기 - 실기
    • 생각 정리

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • code deploy
  • 스프링 부트 무중단 웹 서비스
  • 알고리즘 #백준강의기초편 #코딩테스트
  • 삼성기출 #2023 #상반기
  • 코딩테스트 #삼성기출 #구현 #시뮬레이션
  • 프로그래머스 #카카오기출 #레벨2
  • 스프링 #AOP
  • nginx
  • 삼성기출 #백준강의문제편
  • ci/cd
  • 슬라이딩 윈도우 #덱
  • 슬라이딩 윈도우
  • 스프링 #인터셉터 #AOP #필터
  • DevOps
  • DMZ
  • Github Actions

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Carnival7

Change Developer

코딩 테스트/삼성 기출

2023상_포탑 부수기 (2024/03/30 업데이트)

2023. 5. 9. 10:27

https://www.codetree.ai/training-field/frequent-problems/problems/destroy-the-turret/description

 

코드트리 | 코딩테스트 준비를 위한 알고리즘 정석

최고의 알고리즘 전문가들이 체계적인 코딩테스트 문제 유형 분류와 학습 커리큘럼을 제시합니다. 알고리즘 학습의 A to Z를 경험해보세요!

www.codetree.ai

해설

  1. 초기 설정
    1. 공격시점, 공격관여 맵을 만들고, 관련된 함수 실행 시 지속 업데이트한다.
    2. 공격자, 공격대상의 위치를 따로 선정한다.
    3. 탐색 방향은 우,하,좌,상 순서로 한다. 이를 통해, 레이저 공격 시 만약 경로의 길이가 똑같은 최단 경로가 2개 이상이라면, 우/하/좌/상의 우선순위대로 먼저 움직인 경로가 선택된다.
    4. 8가지 대각선 탐색 방향은 따로 설정한다.
  2. 전체 프로세스
    1. 라운드는 1부터 K까지 진행한다.
      1. 공격자 선정
      2. 공격대상 선정
      3. 공격 시도
        1. 레이저
        2. 포탄
      4. 포탑 부서짐 - 공격력 0 이하인 포탑은 0으로 설정
      5. 포탑 수 확인 - 부서지지 않은 포탑 1개만 남아있을 경우 중지
      6. 포탑 정비 - 공격력 1이상인 포탑의 공격력 +1
      7. 공격관여 맵 초기화
  3. 개별 함수 설명
    1. 공격자 선정
      1. 맵을 전체 탐색하며, 공격력 0인 대상 제외하고 [공격력, 공격시점, 행+열, 열, 행] 을 arr 배열에 넣는다.
      2. 배열을 공격력 오름차순, 공격시점/행+열/열 내림차순으로 정렬한다.
      3. 맨 첫 번째 요소가 공격자다.
      4. 공격자의 공격력을 n+m만큼 증가시키고
      5. 공격관여와 공격시점을 업데이트한다
    2. 공격대상 선정
      1. 맵을 전체 탐색하며, 공격력 0인 대상과 공격자 제외하고 [공격력, 공격시점, 행+열, 열, 행] 을 arr 배열에 넣는다
      2. 배열을 공격력 내림차순, 공격시점/행+열/열 오름차순으로 정렬한다.
      3. 맨 첫 번째 요소가 공격대상이다.
      4. 공격관여를 업데이트한다
  4. 공격 시도
    1. BFS 탐색으로 공격자~공격대상 최단 루트를 찾는다.
      1. 공격력 0인 부서진 포탑을 제외하고 맵을 일반적인 BFS 로 탐색하되, 아래 사항을 주의한다.
        1. 만약 맵 범위를 벗어난 곳을 탐색할 경우, 격자 반대편으로 점프한다.(outBound)
        2. parent 딕셔너리를 사용하여 최단 루트를 저장한다. parent 의 key 에는 다음 탐색할 칸, value 에는 현재 탐색 중인 칸이 튜플 형식으로 저장된다.
        3. 만약 탐색 도중 공격대상이 위치한 칸을 찾지 못할 경우 중지하고, 최단 경로가 존재하지 않음을 반환한다.
      2. 최단 루트를 route 배열에 담아 공격자~공격대상 순으로 정렬하여 반환한다.
    2. 최단 루트가 존재하면 레이저 공격
      1. 공격대상의 공격력을 공격자의 공격력만큼 감소시킨다.
      2. 최단 루트에서 공격자, 공격대상을 제외한다.
      3. 공격 대상 제외한 경로에 있는 포탑들 공격력 절반만큼 피해, 공격관여 업데이트 한다.
    3. 최단 루트가 존재하지 않으면 포탄 공격
      1. 공격대상의 공격력을 공격자의 공격력만큼 감소시킨다.
      2. 공격대상 주위 8개 공격 - 공격력 절반만큼(공격자 해당X), 공격관여 업데이트 한다.
        1. 이때, 초기 설정했던 8가지 대각선 탐색 방향을 사용한다.
        2. 만약 맵 범위를 벗어난 곳을 탐색할 경우, 격자 반대편으로 점프한다.(outBound)

소스코드

from collections import deque

n,m,K=map(int,input().split())
a=[list(map(int,input().split())) for _ in range(n)] # 공격력
b=[[0]*m for _ in range(n)] # 공격시점
c=[[False]*m for _ in range(n)] # 공격관여

ax,ay=-1,-1 # 공격자
tx,ty=-1,-1 # 공격대상

#  우,하,좌,상
dx=[0,1,0,-1]
dy=[1,0,-1,0]

# 대각선
dx1=[-1,-1,-1,0,0,1,1,1]
dy1=[-1,0,1,-1,1,-1,0,1]

def selectAttacker(round):
    global ax,ay,a,b,c

    # 공격자 선정
    arr=[]
    for x in range(n):
        for y in range(m):
            if a[x][y]==0:continue
            arr.append([a[x][y],b[x][y],x+y,y,x])
    arr.sort(key=lambda x:(x[0],-x[1],-x[2],-x[3]))
    ax,ay=arr[0][-1],arr[0][-2]

    # 공격력 증가
    a[ax][ay]+=n+m
    # 공격관여와 공격시점 업데이트
    c[ax][ay]=True
    b[ax][ay]=round

def selectAttacked(round):
    global tx,ty,a,b,c

    # 공격대상 선정
    arr=[]
    for x in range(n):
        for y in range(m):
            if a[x][y]==0:continue
            if (x,y)==(ax,ay): continue
            arr.append([a[x][y],b[x][y],x+y,y,x])
    arr.sort(key=lambda x:(-x[0],x[1],x[2],x[3]))
    tx,ty=arr[0][-1],arr[0][-2]

    # 공격관여 업데이트
    c[tx][ty] = True


def inBoard(nx,ny):
    if 0<=nx<n and 0<=ny<m:
        return True
    return False

def outBoard(nx,ny):
    if nx==-1:
        nx=n-1
    if nx==n:
        nx=0
    if ny==-1:
        ny=m-1
    if ny==m:
        ny=0
    return [nx,ny]

def bfs():

    # 공격자 - 공격대상까지의 최단 루트 탐색
    q=deque()
    q.append((ax,ay))
    visit=[[False]*m for _ in range(n)]
    visit[ax][ay]=True
    parent=dict()
    ok=False # 최단 루트 존재 여부

    while q:
        x,y=q.popleft()
        for k in range(4):
            nx,ny=x+dx[k],y+dy[k]
            # 보드 범위 벗어날 경우 격자 반대편으로 점프
            if not inBoard(nx,ny):
                nx,ny=outBoard(nx,ny)
            if a[nx][ny]>0 and visit[nx][ny]==False:
                visit[nx][ny]=True
                q.append((nx,ny))
                parent[(nx,ny)]=(x,y)
                # 공격 대상 찾았으면 최단 경로 존재
                if (nx,ny)==(tx,ty):
                    ok=True
    # 최단 경로 존재하지 않으면 False 반환
    if ok==False:
        return [None,False]

    start=(ax,ay)
    end=(tx,ty)
    current=end
    route=[current]
    while current!=start:
        current=parent[current]
        route.append(current)
    route.reverse() # 최단 루트

    return [route,True]

def laser(route):
    global a,c

    # 공격대상 공격력 감소
    a[tx][ty]-=a[ax][ay]
    # 최단 루트에서 공격자, 공격대상 제외
    route=route[1:-1]
    # 공격 대상 제외한 경로에 있는 포탑들 공격력 절반만큼 피해, 공격관여 업데이트
    for x,y in route:
        a[x][y]-=a[ax][ay]//2
        c[x][y]=True

def canon():
    global a,c

    # 공격대상 공격력 감소
    a[tx][ty]-=a[ax][ay]
    # 공격대상 주위 8개 공격 - 공격력 절반만큼(공격자 해당X), 공격관여 업데이트
    x,y=tx,ty
    for k in range(8):
        nx,ny=x+dx1[k],y+dy1[k]
        if not inBoard(nx, ny):
            nx, ny = outBoard(nx, ny)
        if a[nx][ny] > 0 and (nx,ny)!=(ax,ay):
            a[nx][ny]-=a[ax][ay]//2
            c[nx][ny]=True

def attack():
    route,ok = bfs()
    # 최단 경로 존재하면 레이저 공격
    if ok:
        laser(route)
    # 최단 경로 존재하지 않으면 포탄 공격
    else:
        canon()

def zeroCheck():
    global a

    for x in range(n):
        for y in range(m):
            if a[x][y]<=0:
                a[x][y]=0

def stop():
    cnt=0
    for x in range(n):
        for y in range(m):
            if a[x][y]>0:
                cnt+=1
    if cnt==1:
        return True
    return False

def fix():
    global a

    for x in range(n):
        for y in range(m):
            if a[x][y]==0 or c[x][y]:continue
            a[x][y]+=1

for round in range(1,K+1):
    # 공격자 선정
    selectAttacker(round)
    # 공격대상 선정
    selectAttacked(round)
    # 공격 시도
    attack()
    # 포탑 부서짐
    zeroCheck()
    # 포탑 수 확인 - 부서지지 않은 포탑 1개만 남아있을 경우 중지
    ok=stop()
    if ok:
        break
    # 포탑 정비
    fix()
    # 공격 관여 초기화
    c=[[False]*m for _ in range(n)] # 공격관여

max_val=-1
for x in range(n):
    for y in range(m):
        max_val=max(max_val,a[x][y])

print(max_val)

'코딩 테스트 > 삼성 기출' 카테고리의 다른 글

2017상_자율주행 자동차  (0) 2024.06.08
2024상_마법의 숲 탐색  (0) 2024.06.08
2023상_토끼와 경주  (0) 2023.05.08
2022상_예술성  (0) 2023.04.01
2022하_코드트리 빵  (0) 2023.03.29
    '코딩 테스트/삼성 기출' 카테고리의 다른 글
    • 2017상_자율주행 자동차
    • 2024상_마법의 숲 탐색
    • 2023상_토끼와 경주
    • 2022상_예술성
    Carnival7
    Carnival7

    티스토리툴바