[백준] 19538번: 루머

가영·2021년 9월 6일
0

알고리즘

목록 보기
38/41

문제

당신은 루머를 믿는가?

한 유명 심리학 실험에서는 사람들에게 두 개의 줄을 보여주고, 어떤 줄이 더 긴지 말하라 했다. 사실 한 사람을 제외하고 나머지는 실험자에 의해 사전에 조작된 사람들이었다. 조작된 사람들은 사실상 더 짧은 줄을 더 길다고 말했다. 주변 모두가 같은 답변을 하자, 진짜 피실험자 또한 짧은 줄이 더 길다고 말했다. 이 실험은 사람들이 주변인의 영향을 강하게 받는다는 것을 보여주었는데, 루머도 이와 같다.

루머는 최초 유포자로부터 시작한다. 최초 유포자는 여러 명일 수 있고, 최초 유포자를 제외하고 스스로 루머를 만들어 믿는 사람은 없다.

매분 루머를 믿는 사람은 모든 주변인에게 루머를 동시에 퍼트리며, 군중 속 사람은 주변인의 절반 이상이 루머를 믿을 때 본인도 루머를 믿는다.

루머를 믿는 순간부터 다른 말은 듣지 않기 때문에, 한번 믿은 루머는 계속 믿는다.

이때, 사람들이 루머를 처음 믿기 시작하는 시간을 알아내 보자.

입력

첫째 줄에 사람의 수 NN이 주어진다. (1N200 0001 \leq N \leq 200\ 000) 이는 11번 사람부터 NN번 사람까지 있음을 의미한다.

둘째 줄부터 NN개의 줄이 주어진다. 이 중 i(1iN)i(1 \leq i \leq N)번째 줄에는 ii번 사람의 주변인들의 번호와 입력의 마지막을 나타내는 0이 공백으로 구분되어 주어진다. 번호는 11 이상 NN 이하의 자연수이고, 같은 줄에 중복된 번호는 없다. 자기 자신이 주변인이거나 일방적으로 주변인인 경우는 없으며, 전체 양방향 주변인 관계는 1 000 0001\ 000\ 000개를 넘지 않는다.

다음 줄에는 루머를 퍼뜨리는 최초 유포자의 수 MM이 주어진다. (1MN)(1 \leq M \leq N)

출력

NN개의 정수 t1,t2,,tNt_1,t_2,\cdots,t_N을 공백 단위로 출력한다. tit_iii번 사람이 루머를 처음 믿기 시작한 시간(분)이며, 충분히 많은 시간이 지나도 루머를 믿지 않을 경우 1-1이다. 최초 유포자는 루머를 00분부터 믿기 시작했다고 생각한다.
마지막 줄에는 최초 유포자의 번호가 공백으로 구분되어 주어진다. 최초 유포자의 번호는 중복되지 않는다.


풀이

정석은 이게 아닐 것 같다. 파이썬3으로는 시간초과가 났다.
나는
deppcopy를 사용해서 배열을 만들었다. 굳이 이럴필요는 없는데 처음에 이런 방식으로 코드를 짜버려서 그냥 이렇게 놔두었다.

이 문제의 특징은 주변인이 반 이상이 믿을 때 그 사람이 루머를 믿게된다는 조건때문이다.
보통 bfs는 도달하면 바로 visit 한 걸로 처리를 하지만 이 문제에서는 루머를 믿고있는 주변인의 명수를 체크해줘야했다.

그래서 큐안에 집어넣기 전 조건문이 다음과 같다.

if ans[e] == -1 and trust[e] >= (len(graph[e])+1)//2:
    ans[e] = ans[curr] + 1
    que.append(e)

참고로 절반 이상을 수로 나타내려면
(주변인의 수 + 1) // 2 로 표현할 수 있다 (이렇게 해야 짝 홀 모두 적용 가능)

구글링했는데 다른 파이썬 풀이는 못찾아서 채점현황을 봤는데 다른 사람들도 나랑 비슷하게 풀었다!

조금 더 효율적인 풀이로는, trust[i]를 따로 나두고 매번 비교하지 않고,
trust[i]를 (i번째 사람의 주변인의 수 + 1) // 2로 초기화하고
주변인이 루머를 믿게되면 그걸 감소연산을 해서 0이되면! i번째 사람도 루머를 믿게하는 식이었다.

끝~


아 이거 왠지 익숙하다 했는데
작년 UCPC 예선 문제였다.. 넘 추억이다. 내가 그 대회 문제를 푸는 날이 올줄이야 장하다 가영아 >_<

0개의 댓글