새소식

PS/백준

[백준/20304] 비밀번호 제작 (Python)

  • -

Problem : https://www.acmicpc.net/problem/20304

 

20304번: 비밀번호 제작

서강대학교 전산실에서 보안직원으로 일하는 향빈이는 한 통의 이메일을 받게 되었다. 이메일에는 서버 관리자 계정에 대한 비정상적인 로그인 시도가 감지되었다는 내용이 적혀 있었고, 첨부

www.acmicpc.net

 

Difficulty : Platinum 5

 

Status : Solved

 

Time : 00:32:12

 


 

문제 설명

 

더보기

 

서강대학교 전산실에서 보안직원으로 일하는 향빈이는 한 통의 이메일을 받게 되었다. 이메일에는 서버 관리자 계정에 대한 비정상적인 로그인 시도가 감지되었다는 내용이 적혀 있었고, 첨부된 파일에는 지금까지 로그인 시도에 사용된 비밀번호 목록이 있었다. 참고로, 서버 관리자 계정의 비밀번호로는 0 이상 N 이하의 정수 중 하나를 사용할 수 있다.

두 비밀번호의 안전 거리는 이진법으로 표현한 두 비밀번호의 서로 다른 자리의 개수로 정의한다. 예를 들어 3을 이진법으로 표현하면 0011, 8을 이진법으로 표현하면 1000이 되고, 이때 서로 다른 자리의 개수는 3개이므로 3과 8의 안전 거리는 3이 된다.

어떤 비밀번호의 안전도는 지금까지 로그인 시도에 사용된 모든 비밀번호와의 안전 거리 중 최솟값으로 정의한다. 예를 들어 지금까지 로그인 시도에 사용된 비밀번호가 3과 4이라고 가정하면, 새로운 비밀번호 8에 대해 3과 8의 안전 거리는 3, 4와 8의 안전 거리는 2이므로 비밀번호 8의 안전도는 2가 된다.

향빈이는 해커가 비밀번호를 알아내기까지의 시간을 최대한 늦추기 위해 현재 사용 중인 관리자 계정 비밀번호의 안전도가 가장 높게끔 바꾸고 싶다. 이때, 안전도가 제일 높은 비밀번호의 안전도를 구하여라.

 

 

입력 및 출력

 

더보기

입력

 

첫째 줄에 관리자 계정 비밀번호의 최댓값을 나타내는 정수 N이 주어진다. (0 <= N <= 1000000)

둘째 줄에는 로그인 시도에 사용된 비밀번호의 개수를 나타내는 정수 M이 주어진다. (1 <= M <= 100000)

셋째 줄에는 로그인 시도에 사용된 비밀번호 값인 정수 p_1, p_2, ... , p_M이 주어진다. (0 <= p_i <= N)

 

출력

 

안전도가 제일 높은 비밀번호의 안전도를 출력한다.

 

입력 예시

 

10
2
3 4

 

출력 예시

 

2

 

 


 

풀이

 

안전도가 0인 케이스, 즉 해킹 시도로 간주되는 숫자들로부터 시작해보자. 이 숫자들의 각 이진법 자릿수를 변경하고 이 횟수를 기억한다면, 그 횟수가 곧 안전 거리가 된다. 또한, 이론상 이러한 자릿수 변경을 통해 0 이상 N 이하의 모든 정수를 방문 가능하다는 것을 알 수 있다. 즉 모든 초기 숫자들은 0이상 N이하의 임의의 숫자를 방문할 수 있고, 이들 안전도의 최솟값이 안전 거리이므로 비트마스킹을 통한 BFS로 해결 가능하다.

 

  • 비트 뒤집기는 XOR을 사용하면 편하다.
  • 최소 안전도를 저장하는 visited 배열 외에도, 초기 숫자에서 어떤 점이 달라졌는지 저장해야 중복 방문을 피할 수 있다.

 

 

풀이 코드

from collections import deque
import sys
input = sys.stdin.readline
MAX = float('inf')

N = int(input())
M = int(input())
visited = [MAX]*(N+1)
q = deque()

for n in map(int, input().split()) :
  visited[n] = 0
  q.append((n, 0, 0))

while q :
  n, cnt, changed = q.popleft()
  for i in range(21) :
    var = n ^ (1 << i)
    if changed & (1 << i) or var > N :
      continue
    if visited[var] > cnt + 1 :
      visited[var] = cnt + 1
      q.append((var, cnt + 1, changed | (1 << i)))

print(max(visited))

풀이 완료!

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.