코딩 테스트

[코드트리 챌린지] 2022 삼성 하반기 오전1번 기출문제 싸움땅 - 파이썬 리뷰

코드트리애호가 2023. 9. 25. 18:41

 

 

아 DP 좀 이해해서 점화식 세워서 풀수있엇는데 ㅋㅋㅋ 뭔가 이상해져서 실패 ㅋㅋ

이런..

0,0에서 n-1,n-1 까지는 쉬운데

0,n-1 에서 n-1,0 까지 점화식을 세우다가.. 실패해버렸다 이런 제길 거의다 풀었는데 ㅋㅋ...

점화식문제는 다음 실력진단때 다시보면 할수있을꺼같다 

 

 

 

 

 

삼성 기출문제 싸움땅 가보자!!!!!!!!!!!

 

 

이번문제는 푸는데 2일이 걸렸고. 

 

가장크게 걸린 부분이 2가지가 있다. 

문제를 풀고 아주 기분 좋았다.

 

왜냐하면,, 6개월 전에는 TC3번에서 막혀서 풀지도 못했고 

 

문제 방식을 이상하게 풀고있었기 때문. 한번 리뷰해보자. 

 

  https://www.codetree.ai/training-field/frequent-problems/problems/battle-ground?&utm_source=clipboard&utm_medium=text 

 

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

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

 

 

 

 

 

이제는 할수있다 보인다...

 

삼성 기출문제의 가장 어려운점..

구현..? 

알고리즘?

 

 

아니.

 

 

국어 <<<<<

 

삼성에서 말하는대로 순서 그대로 짰느냐.

설계가 중요한것같다. 

 

작년에 내가 어떻게 풀었는지 리뷰해보면.. 

 

maps 라는 배열 하나에 

((사람번호,총),땅떨어진총)

이런식으로 관리를 했엇다... (실화냐 진짜 ㅋㅋ 왤케 구겨넣으려고 함?? 

 

특히나 사람위치를 또 사람 배열로 관리했엇고.. 땅에 떨어진총을 또 공격력이 쎈놈으로 정렬하는데 또 하루 종일 걸렸다.. 

왜냐면 len 써서 또 써야하고.. 정렬하고 [0] 값 뺀다음에.. 

 

이러니까 코테 풀다가 예외에서 터져버리지 ㅋㅋ 특히나 싸움에서 진사람 구현하다가 아마 포기했던것같다. 아주 이상하게 만들어서. .. 

 

 

 

이번에 2일동안 풀면서 구현이 어려웠던부분?

은 딱히 없엇다(근데 2일이나 걸림? ) 

 

이유는

 

패배한 사람의 예외 처리를 하다가 

if 문처리할때 break 를 넣지 않아서 

오른쪽90도 씩 돌리고 빈공간이있으면 가야하는데 가장 마지막에 나오는 빈공간에 이동해서

이부분을 디버그 하느라 시간이 오래걸렸다.

 

!!!그래도!! Vscode 로 디버그 하는방법을 알아서 실제 삼성 코테에서 문제풀때 좋게 작용할꺼같다. !! 

 

 

그외 문제에서 어려웠던 부분이라고 하면 

최소heapq 를 사용해서 땅에 떨어진 총을 관리했떤거 ( 이건 생각하면 지렷던거같다. 심지어 류호석 좌도 나하고 같이 풀어서 기분이 좋았다. 하지만 개같이 if문처리에서 탈락 ㅋㅋ ) 

 

특히나 땅에 떨어진 총이 있을때 뭐

총이 0 = (총이없는 상태) 면 뭐 len(maps[x][y]) 해가지고 비교하고...

 

그냥 야랄을 떨엇다..

 

 

이런 습관을 줄여야하는데..

 

그냥 단순하게 생각해서

 

만약 바닥에 있는 0 이 총이라고 쳐도 총 무기가 2 라면, -2로 바꾼다음에 heappush 해버리면 자동으로 정렬되고, 

그냥 가져오면되는거다.

 

만약에 서로 둘다 0,0 아무 총도 없고 바닥에도 없어도 0 넣고 그냥 0 가져오면 해결. 무엇을 그렇게 처리하다가 시간이 오래걸렸는지 모르겠다. 

아마 안좋은 악습 = maps[x][y] 에다가 다 때려넣고 하던 습관이 남아있던거 같다.

 

 

이제는 달라졋다 !!!!!!!

 

 

그리고 관련 C++ 언어로 풀던 류호석좌의 코드 처리를 보니 

 

for i in range(n) : 

    for j in range(n): 

        if i == j : continue 

하는 위에 구문은 굉장히 좋은것같다.

괜히 저거 인덱스0번 가져오고 저 나머지애들 하나하나 처리했엇는데

저 continue 처리면 그럴 필요도 없고 볼때 훨씬 편하다. 

 

또 메인 함수단을

 

for round in range(k) :
    if deb :
            player_debug(round)
    for man in range(m) :
        if normal_move(man) : #일반이동(격자 반대편뒤돌아오기) True하면 그냥 총 얻고 끝
            acquire_gun(man)
            continue
        battle(man)#만약 이겻다면? True 여기서 진놈은 총을 다 떨궈야함.
 
이렇게 작성했다. 

좀더 세분화했으면 battle() 함수에서 출력물이 (실패자,승리자)가 나오면

drop_gun(실패자)

accquire_gun(승리자)

처리를 했으면 메인함수에서 더 잘보이지 않았을까? 생각든다.

 

 

어찌됐건 6개월전에 못풀던 문제를 내가 구상한 방법으로 풀 수 있어서 상당히 기분좋았다. 이기세를 몰아 다음 문제도 풀어보자. 

-- if문 처리에서 빵꾸가 나버렸지만.. 

 

from collections import deque
import sys
import heapq

n,m,k= map(int,input().split())
player_point = [0]*m
player_location = []
player_gun = [0]*m
player_power=[]
battle_check=[]
gun_map = [ [[] for _ in range(n)] for _ in range(n)]
for i in range(n) :
    temp = list(map(int,input().split( )))
    for j in range(n):
        heapq.heappush(gun_map[i][j],-temp[j])

dxs=[-1,0,1,0]
dys=[0,1,0,-1]
for i in range(m) :
    x,y,d,s = map(int,input().split())
    x-=1
    y-=1
    player_location.append((x,y,d))
    player_power.append(s)
    #방향
    #s는 초기 능력치

def in_range(x,y) :
    return 0<=x<n and 0<=y<n

def normal_move(player) :
    #플레이어는 해당 번호
    x,y,d = player_location[player]

    nx,ny = x+dxs[d],y+dys[d]
    if in_range(nx,ny):
        player_location[player]= (nx,ny,d)
        for j in range(m):
            tx,ty,_ = player_location[j]
            if j == player : continue
            if nx ==tx and ty == ny :
                battle_check.append((player,j))#이두놈 싸워야한다.
                return False
    else :
        d = (d+2)%4
        nnx,nny=x+dxs[d],y+dys[d]# 방향 바꾸고 다음칸으로
        player_location[player] = (nnx,nny,d)
        for j in range(m):
            tx,ty,_ = player_location[j]
            if j == player : continue
            if nnx ==tx and nny == ty :
                battle_check.append((player,j))#이두놈 싸워야한다.
                return False

    return True

def acquire_gun(player):
    x,y,d = player_location[player]

    my_gun = player_gun[player]

    heapq.heappush(gun_map[x][y],-my_gun)
    max_gun = (heapq.heappop(gun_map[x][y])) #최대값을 빼온다.
    max_gun = -(max_gun)
    player_gun[player] = max_gun
    if deb:
        print(player,'플레이어는',max_gun,'의총을먹엇다.')
       

    return


def fail_move(player) : #졌으니까 총을 자리에 떨구고 이동해야한다.
    possible = False
    x,y,d = player_location[player]
    gun_power = player_gun[player] # gun power가 0이면 걍 안넣기

    if gun_power != 0 :  #총이있다면? 그 이전자리에 떨궈놔야한다.
        if gun_map[x][y][0] == 0 :#만약 빈자리라면,
            heapq.heappop(gun_map[x][y]) # 0빼버리고
            heapq.heappush(gun_map[x][y],(-gun_power))
            if deb:
                print(player,'는',gun_power,'의총을 떨궛다.')
            player_gun[player] = 0 #총 떨궜다 처리
        else : # 둘다 총이있다?
            heapq.heappush(gun_map[x][y],(-gun_power))
            if deb:
                print(player,'는',gun_power,'의총을 떨궛다.')
            player_gun[player] = 0 #총 떨궜다 처리

    nx,ny = x+dxs[d],y+dys[d] # 그다음곳 찾기
    if in_range(nx,ny) : # 갈수있고
        chk = 0
        for j in range(m):
            tx,ty,td = player_location[j]
            if player == j : continue
            if (nx == tx and ny == ty): #똑같은게 하나라도 있으면
                chk = 1
        if chk != 1 :
            player_location[player] = nx,ny,d
        else :
            possible=True
    else :
        possible = True
       
    if possible :# 이동 불가일때 90도로  돌리고 진행시켜본다.
        for _ in range(3) :
            possible2 = False
            d = (d+1)%4
            nnx,nny = x+dxs[d],y+dys[d]
           
            if in_range(nnx,nny) :

                for z in range(m):
                    t1x,t1y,t1d = player_location[z]
                    if z == player : continue
                    if t1x == nnx and t1y == nny : # 같은게있다면
                        #얘는 안된다.  
                        possible2 = True
                        continue # 다음 공간 찾기.
            else :
                possible2 = True # 안된다.

            if possible2 == False :
                #print('chk')
                player_location[player] = (nnx,nny,d)
                break
           
        #print('이래도안나가??',x,y,'플레이어:',player)

    #이동한다음 총 먹으면된다.
    if deb :
        (nnx,nny,d) = player_location[player]
        print('실패자',player,'는',nnx,nny,'로 이동했다.',d,'의방향을가짐')
    acquire_gun(player)
    return


def battle(player) :
    # 배틀을 붙을수있는 사람은 무조껀 2명이다.
    p1,p2 = battle_check.pop() #싸울놈을 빼준다.
    #p1이 플레이어
    p1_power = player_gun[p1] + player_power[p1]
    p2_power = player_gun[p2] + player_power[p2]
    win_pandan = False
    if p1_power >= p2_power :
        if p1_power == p2_power :
            #같을때는 초기능력치
            if player_power[p1] > player_power[p2] : #p1이 이겼다!
                win_pandan = True
            else :
                win_pandan = False
        else :
            win_pandan= True

    points = abs(p1_power - p2_power)

    if win_pandan : # p1 이 이겼다면, 진놈 총떨구기 시전
        player_point[p1] += points
        if deb:
            print(p1,'승리',p2,'패배',points,'획득')
        fail_move(p2)
        acquire_gun(p1)
    else :          #졌다면 총 떨구고 이긴놈 총먹게
        player_point[p2] += points
        if deb:
            print(p2,'승리',p1,'패배',points,'획득')
        fail_move(p1)
        acquire_gun(p2)
    return

for round in range(k) :
    if deb :
            player_debug(round)
    for man in range(m) :
        if normal_move(man) : #일반이동(격자 반대편뒤돌아오기) True하면 그냥 총 얻고 끝
            acquire_gun(man)
            continue
        battle(man)#만약 이겻다면? True 여기서 진놈은 총을 다 떨궈야함.

if deb :
    player_debug(round)
for i in player_point:
    print(i,end=' ')