본문 바로가기

Problem Solving/백준BOJ

[백준BOJ] 1043번 거짓말.py

728x90
반응형
SMALL

 

백준 저지에서 거짓말을 파이썬을 통해 풀어 보았다. 

 

https://www.acmicpc.net/problem/1043

 

1043번: 거짓말

지민이는 파티에 가서 이야기 하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게

www.acmicpc.net

1043번 거짓말.py

 

GitHub - tomy9729/Algorithm: 🐗 내가 직접 작성한 내 코드 🐗

🐗 내가 직접 작성한 내 코드 🐗. Contribute to tomy9729/Algorithm development by creating an account on GitHub.

github.com

 

 

1043번 거짓말

문제

지민이는 파티에 가서 이야기하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게 과장해서 말한다. 당연히 과장해서 이야기하는 것이 훨씬 더 재미있기 때문에, 되도록이면 과장해서 이야기하려고 한다. 하지만, 지민이는 거짓말쟁이로 알려지기는 싫어한다. 문제는 몇몇 사람들은 그 이야기의 진실을 안다는 것이다. 따라서 이런 사람들이 파티에 왔을 때는, 지민이는 진실을 이야기할 수밖에 없다. 당연히, 어떤 사람이 어떤 파티에서는 진실을 듣고, 또 다른 파티에서는 과장된 이야기를 들었을 때도 지민이는 거짓말쟁이로 알려지게 된다. 지민이는 이런 일을 모두 피해야 한다.
사람의 수 N이 주어진다. 그리고 그 이야기의 진실을 아는 사람이 주어진다. 그리고 각 파티에 오는 사람들의 번호가 주어진다. 지민이는 모든 파티에 참가해야 한다. 이때, 지민이가 거짓말쟁이로 알려지지 않으면서, 과장된 이야기를 할 수 있는 파티 개수의 최댓값을 구하는 프로그램을 작성하시오.

설명

처음 문제를 읽을 때는 골드 4치고 쉽다고 생각했는데 역시나 생각처럼 쉬운 문제는 아니었다. 결론만 말하면 BFS로 풀긴 했는데 'BFS로 풀어야겠다'라고 깨우친 과정까지 오래 걸렸다. 처음에는 단순하게 각 파티에 "진실을 아는 사람" 사람이 없으면 거짓말을 할 수 있다고 생각했다. 근데 생각해보니 파티에 "진실을 아는 사람"이 없더라도 다른 파티에서 "진실을 아는 사람"한테 진실을 듣고 온 사람이 있다면 지민이는 거짓말을 할 수 없다. 그러면 모든 파티를 한 번 순회하여 "진실을 아는 사람"에 진실을 들은 사람도 "진실을 아는 사람"에 추가하여 같은 방법으로 작성했다. 역시나 틀렸다. 한 번의 순회로는 "진실을 아는 사람"을 모두 파악하지 못하는 경우가 존재했다. 그렇다고 무작정 여러 번 순회하자니 비효율적이다. 이 대목에서 그래프를 떠올렸다.

 

그래프를 통해 같은 파티에 참가한 사람들끼리 양방향 그래프로 연결하면 한 번의 순회로 모든 사람의 연결 고리를 기록할 수 있다. 또한 "진실을 아는 사람"을 따로 추가할 필요도 없다. 그래프로 연결되어 있기 때문에 그래프를 따라 만나는 사람이 최초의 "진실을 아는 사람"에 포함되는지만 파악하면 된다. 

 

양방향 그래프를 생성하는 과정이나, 그래프를 통해 연결된 사람이 "진실을 아는 사람"인지 여부를 파악할 때 set을 사용해서 시간 복잡도를 최소화했다.

 

모든 파티에 대하여 파티에 참가한 사람들끼리 서로 양방향 그래프를 만든다. 다음 각 파티에 참가한 모든 사람을 기준으로 출발하는 BFS를 수행한다. BFS를 따라 탐색하는 과정 중에 "진실을 아는 사람"이 존재한다면 곧바로 함수를 종료한다. 이 경우 지민이는 거짓말을 할 수 없다. 만약 BFS가 끝까지 돌아서 정상적으로 종료된다면 해당 파티에서 지민이는 거짓말을 할 수 있다.

코드

#1043번 거짓말
from collections import deque
def BFS(visit,graph,start,know_people):
  visit[start]=True
  q = deque()
  q.append(start)
  while q :
    now = q.popleft()
    now = list(graph[now])
    for next in now : 
      if visit[next]==False :
        visit[next]=True
        if next in know_people : 
          return 0
        q.append(next)
  return 1
if __name__ == "__main__" :
  n,m = map(int,input().split())
  graph = [set() for _ in range(n+1)]

  know_people = list(map(int,input().split()))
  know_people = set(know_people[1:])
  
  partys=[]
  for i in range(m) :
    party = list(map(int,input().split()))
    people_num = party[0]
    party = party[1:]
    partys.append(party)
    for i in range(people_num) :
      graph[party[i]] = graph[party[i]] | (set(party[:i]) | set(party[i+1:]))

  count = 0
  visit = [False]*(n+1)
  for i in range(m) :
    for j in partys[i] :
      if j in know_people : 
        break
      visit = [False]*(n+1)
      can_lie = BFS(visit,graph,j,know_people)
      if can_lie == 1 :
        count += 1
        break
  print(count)
728x90
반응형
SMALL