Notice
                              
                          
                        
                          
                          
                            Recent Posts
                            
                        
                          
                          
                            Recent Comments
                            
                        
                          
                          
                            Link
                            
                        250x250
    
    
  | 일 | 월 | 화 | 수 | 목 | 금 | 토 | 
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 
| 9 | 10 | 11 | 12 | 13 | 14 | 15 | 
| 16 | 17 | 18 | 19 | 20 | 21 | 22 | 
| 23 | 24 | 25 | 26 | 27 | 28 | 29 | 
| 30 | 
                            Tags
                            
                        
                          
                          - 깊이 우선 탐색
- SQL
- join
- DP
- 자바스크립트
- javascript
- 티스토리챌린지
- 소프티어
- 프로그래머스
- LEVEL 2
- Java
- Lv. 1
- Python
- programmers
- dfs
- Lv. 3
- Lv. 2
- 너비 우선 탐색
- 오블완
- SQL 고득점 KIT
- 백준
- softeer
- bfs
- 동적계획법
- Lv. 0
- Dynamic Programming
- group by
- level 3
- Baekjoon
- 파이썬
                            Archives
                            
                        
                          
                          - Today
- Total
몸과 마음이 건전한 SW 개발자
프로그래머스 [Lv. 3] 카드 짝 맞추기 {언어 : Python} 본문
728x90
    
    
  문제 링크
https://school.programmers.co.kr/learn/courses/30/lessons/72415
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
정답 코드
from collections import deque
def solution(board, r, c):
    minLength = [10000]
    # 방향 탐색
    dr = [-1, 1, 0, 0]
    dc = [0, 0, -1, 1]
    def isValid(nr, nc):
        return 0 <= nr < 4 and 0 <= nc < 4
    
    # 거리 계산
    def calCnt(ar, ac, br, bc, removes):
        if (ar, ac) == (br, bc):
            return 0
        dist = 0
        cnt = 0
        if ar == br:
            if ac > bc:
                for nc in range(ac-1, bc-1, -1):
                    if board[ar][nc] and board[ar][nc] not in removes:
                        cnt += 1
                        dist = cnt
                    else:
                        dist += 1
            else:
                for nc in range(ac+1, bc+1):
                    if board[ar][nc] and board[ar][nc] not in removes:
                        cnt += 1
                        dist = cnt
                    else:
                        dist += 1
            if cnt == 0 and (bc == 0 or bc == 3):
                dist = 1
        elif ac == bc:
            if ar > br:
                for nr in range(ar-1, br-1, -1):
                    if board[nr][ac] and board[nr][ac] not in removes:
                        cnt += 1
                        dist = cnt
                    else:
                        dist += 1
            else:
                for nr in range(ar+1, br+1):
                    if board[nr][ac] and board[nr][ac] not in removes:
                        cnt += 1
                        dist = cnt
                    else:
                        dist += 1
            if cnt == 0 and (br == 0 or br == 3):
                dist = 1
        else:
            dist1, dist2, dist3, dist4 = 0, 0, 0, 0
            cnt1, cnt2, cnt3, cnt4 = 0, 0, 0, 0
            # 왼쪽 위
            if ar > br and ac > bc:
                # 왼쪽으로 가서 위로
                for nc in range(ac-1, bc-1, -1):
                    if board[ar][nc] and board[ar][nc] not in removes:
                        cnt1 += 1
                        dist1 = cnt1
                    else:
                        dist1 += 1
                if cnt1 == 0 and bc == 0:
                    dist1 = 1
                for nr in range(ar-1, br-1, -1):
                    if board[nr][bc] and board[nr][bc] not in removes:
                        cnt2 += 1
                        dist2 = cnt2
                    else:
                        dist2 += 1
                if cnt2 == 0 and br == 0:
                    dist2 = 1
                    
                # 위로가서 왼쪽으로
                for nr in range(ar-1, br-1, -1):
                    if board[nr][ac] and board[nr][ac] not in removes:
                        cnt3 += 1
                        dist3 = cnt3
                    else:
                        dist3 += 1
                if cnt3 == 0 and br == 0:
                    dist3 = 1
                for nc in range(ac-1, bc-1, -1):
                    if board[br][nc] and board[br][nc] not in removes:
                        cnt4 += 1
                        dist4 = cnt4
                    else:
                        dist4 += 1
                if cnt4 == 0 and bc == 0:
                    dist4 = 1
                
            elif br > ar and ac > bc:
                # 왼쪽 아래
                # 왼쪽으로 가서 아래
                for nc in range(ac-1, bc-1, -1):
                    if board[ar][nc] and board[ar][nc] not in removes:
                        cnt1 += 1
                        dist1 = cnt1
                    else:
                        dist1 += 1
                if cnt1 == 0 and bc == 0:
                    dist1 = 1
                for nr in range(ar+1, br+1):
                    if board[nr][bc] and board[nr][bc] not in removes:
                        cnt2 += 1
                        dist2 = cnt2
                    else:
                        dist2 += 1
                if cnt2 == 0 and br == 3:
                    dist2 = 1
                
                # 아래로 가서 왼쪽으로
                for nr in range(ar+1, br+1):
                    if board[nr][ac] and board[nr][ac] not in removes:
                        cnt3 += 1
                        dist3 = cnt3
                    else:
                        dist3 += 1
                if cnt3 == 0 and br == 3:
                    dist3 = 1
                for nc in range(ac-1, bc-1, -1):
                    if board[br][nc] and board[br][nc] not in removes:
                        cnt4 += 1
                        dist4 = cnt4
                    else:
                        dist4 += 1
                if cnt4 == 0 and bc == 0:
                    dist4 = 1
                    
            elif ar > br and bc > ac:
                # 오른쪽 위
                # 오른쪽으로 가서 위로
                for nc in range(ac+1, bc+1):
                    if board[ar][nc] and board[ar][nc] not in removes:
                        cnt1 += 1
                        dist1 = cnt1
                    else:
                        dist1 += 1
                if cnt1 == 0 and bc == 3:
                    dist1 = 1
                for nr in range(ar-1, br-1, -1):
                    if board[nr][bc] and board[nr][bc] not in removes:
                        cnt2 += 1
                        dist2 = cnt2
                    else:
                        dist2 += 1
                if cnt2 == 0 and br == 0:
                    dist2 = 1
                    
                # 위로 가서 오른쪽으로
                for nr in range(ar-1, br-1, -1):
                    if board[nr][ac] and board[nr][ac] not in removes:
                        cnt3 += 1
                        dist3 = cnt3
                    else:
                        dist3 += 1
                if cnt3 == 0 and br == 0:
                    dist3 = 1
                for nc in range(ac+1, bc+1):
                    if board[br][nc] and board[br][nc] not in removes:
                        cnt4 += 1
                        dist4 = cnt4
                    else:
                        dist4 += 1
                if cnt4 == 0 and bc == 3:
                    dist4 = 1
                        
            else:
                # 오른쪽 아래
                # 오른쪽으로 가서 아래로
                for nc in range(ac+1, bc+1):
                    if board[ar][nc] and board[ar][nc] not in removes:
                        cnt1 += 1
                        dist1 = cnt1
                    else:
                        dist1 += 1
                if cnt1 == 0 and bc == 3:
                    dist1 = 1
                for nr in range(ar+1, br+1):
                    if board[nr][bc] and board[nr][bc] not in removes:
                        cnt2 += 1
                        dist2 = cnt2
                    else:
                        dist2 += 1
                if cnt2 == 0 and br == 3:
                    dist2 = 1
                    
                # 아래로 가서 오른쪽으로
                for nr in range(ar+1, br+1):
                    if board[nr][ac] and board[nr][ac] not in removes:
                        cnt3 += 1
                        dist3 = cnt3
                    else:
                        dist3 += 1
                if cnt3 == 0 and br == 3:
                    dist3 = 1
                for nc in range(ac+1, bc+1):
                    if board[br][nc] and board[br][nc] not in removes:
                        cnt4 += 1
                        dist4 = cnt4
                    else:
                        dist4 += 1
                if cnt4 == 0 and bc == 3:
                    dist4 = 1
                    
            dist = min(dist1+dist2, dist3+dist4)
        # print(ar, ac, br, bc, "dist", dist, removes)   
            
        return dist
    
    # 짝 위치
    dictPairs = dict()
    visitedCards = [0] * 7
    
    # 짝짓기
    for i in range(4):
        for j in range(4):
            card = board[i][j]
            if card and visitedCards[card] == 0:
                # 다른 위치 탐색
                visitedCards[card] = 1
                dq = deque([[i, j]])
                visited = [[0] * 4 for _ in range(4)]
                visited[i][j] = 1
                isFound = False
                while dq and not isFound:
                    sr, sc = dq.popleft()
                    
                    for d in range(4):
                        nr = dr[d] + sr
                        nc = dc[d] + sc
                        if isValid(nr, nc) and visited[nr][nc] == 0:
                            if board[nr][nc] == card:
                                isFound = True
                                dictPairs[card] = [i, j, nr, nc]
                                break
                            else:
                                visited[nr][nc] = 1
                                dq.append([nr, nc])
    # 지워야할 카드 개수
    lenCards = len(dictPairs)
    cards = list(dictPairs.keys())
    removeOrders = []
    visitedDfs = [0 for _ in range(7)]
    def dfs(l, visited):
        if l == lenCards:
            removeOrders.append(visited)
            return
        for card in cards:
            if card in visited:
                continue
            dfs(l+1, visited+[card])
    dfs(0, [])
    
    def calMinLength(l, order, length, sr, sc, removes):
        if minLength[0] <= length:
            return
        if l == lenCards:
            if minLength[0] > length:
                minLength[0] = length
            return
        o = order[l]
        ar, ac, br, bc = dictPairs[o]
        calMinLength(l+1, order, length + calCnt(ar, ac, br, bc, removes) + calCnt(sr, sc, ar, ac, removes), br, bc, removes+[o])
        calMinLength(l+1, order, length + calCnt(br, bc, ar, ac, removes) + calCnt(sr, sc, br, bc, removes), ar, ac, removes+[o])
                
    # 카드 지우기
    for order in removeOrders:
        calMinLength(0, order, 0, r, c, [])
    
    answer = minLength[0] + (lenCards * 2)
    return answer풀이 방법
- 카드의 값과 위치를 딕셔너리 형태로 저장한다.
- 카드 제거 순서를 dfs를 통해서 만든다.
- 카드를 제거하면서 다음과 같이 이동횟수를 계산한다.
- 현재 지점에서 ar, ac로 간 다음 br, bc로 가는 경우
- 현재 지점에서 br, bc로 간 다음 ar, ac로 가는 경우
 
- 이미 제거된 카드는 ctrl + 방향키로 이동이 불가능 하다.
- 따라서 removes로 확인한다.
 
- 카드를 모두 제거 했을 때 minLength와 비교해서 가장 적은 이동횟수로 치환한다.
- 최소 횟수에 카드 제거 할 때 enter를 치므로 총 카드 수 * 2를 더해주면 끝!
느낀점
- 결국 도움 하나도 안 받고 풀었는데 이렇게 어려울 줄은 몰랐다...
728x90
    
    
  '알고리즘 > 풀었지만 다시 보기' 카테고리의 다른 글
| 프로그래머스 [Lv. 3] n + 1 카드게임 {언어 : JavaScript} (3) | 2024.09.13 | 
|---|---|
| 프로그래머스 [Lv. 3] [PCCP 기출문제] 4번 / 수식 복원하기 {언어 : Python} (1) | 2024.09.12 | 
| 프로그래머스 [Lv. 3] 등대 {언어 : Python} [8, 9 런타임 에러 해결] (0) | 2024.09.02 | 
| 프로그래머스 [Lv. 3] 매칭 점수 {언어 : Python} [정규식X] (0) | 2024.08.27 | 
| 프로그래머스 [Lv. 3] 2차원 동전 뒤집기 {언어 : JavaScript} (0) | 2024.08.16 |