- 문제 : https://www.acmicpc.net/problem/1039

 

문제 이해 

- 주어진 수의 i번째 자리수와 j번째 자리수를 k번 바꿔서 타겟 숫자가 될 수 있는지 출력하는 문제다.

- 문제가 그리디 같기도, 브루트포스? 같기도 해서 bfs로 어떻게 풀지 몰랐던 문제다. 

- 주의해야할 점은 두 가지가 있는데, 다음과 같다.

  1. 연산을 한 번 해서 이전과 같은 숫자가 나와도 다른 케이스로 쳐줘야 한다. 그래서 visit를 set으로 구현해서 원소들의 중복을 없애야 한다.

  2. 숫자를 바꿨을 때 가장 앞에 있는 수가 0이면 세지 않는다.  

- 그리고 i, j번째 수를 일일히 바꾸면 시간이 오래 걸리지 않을까 싶었는데 이중 for문으로 i, j를 바꾸면서 진행해야 했다. 

 

풀이 로직

- 입력값을 입력 받은 뒤 visit와 queue를 초기화 한다. 

  visit는 (진행하는 숫자, 연산횟수)를 원소로 가진 set

  queue는 [진행하는 숫자, 연산횟수]를 원소로 가진 배열

- while문으로 bfs를 진행하면서 연산횟수가 k와 같다면 정답 후보이다. 이때 answer = max(answer, 연산횟수)를 통해 가능한 최대값을 계속 업데이트한다.

- 연산횟수가 k가 아니라면 숫자를 배열로 변경한 뒤 이중 for문으로 i번째 수와 j번째 숫자를 바꾼다.

- 바꾼 숫자를 다시 ''.join()으로 하나의 숫자를 만들고 해당 숫자를 이전에 visit 하지 않았다면, visit 처리한 뒤 queue에 추가한다.

- 다른 숫자들도 숫자를 바꿔야 하므로 위에서 바꿨던 숫자를 다시 원상복구한다.

- while문에서 answer의 값이 0이 아니라면 정답이 있으므로 answer를 출력하고, 여전히 0이라면 -1을 출력한다.

 

정답 풀이 

n, k = map(int, input().split())
m = len(str(n))

visit = set()
visit.add((n, 0)) # 숫자, 연산횟수
queue = [[n, 0]]
answer = 0

while queue:
    number, times = queue.pop(0)
    
    if times == k:
        answer = max(answer, number) # 최대 숫자 업데이트
        continue
        
    number = list(str(number))
    for i in range(m - 1):
        for j in range(i + 1, m):
            if i == 0 and number[j] == '0':
                continue
            
            number[i], number[j] = number[j], number[i]
            temp = int(''.join(number))
            if (temp, times + 1) not in visit:
                queue.append([temp, times + 1])
                visit.add((temp, times + 1))
            # 배열 원상복구
            number[i], number[j] = number[j], number[i]
                
if answer == 0:
    print(-1)
else:
    print(answer)

 

 

참고한 블로그 : 백준-1039번-교환-파이썬

'백준 > Search' 카테고리의 다른 글

[bfs/백준] 1525번 : 퍼즐  (0) 2023.05.31
[bfs/백준] 14867번 : 물통  (0) 2023.05.31
[bfs/백준] 9019번 : DSLR  (0) 2023.05.26
[bfs/백준] 16397번 : 탈출  (0) 2023.05.25
[bfs/백준] 3055번 : 탈출  (0) 2023.05.25

+ Recent posts