문제출처 : https://www.acmicpc.net/problem/9466


1. 문제요약

- 학생들이 팀을 이룸

- 1 2 3 4 5 6 7

  3 1 3 7 3 4 6


- 2 -> 1 -> 3(3) <- 5

  4 -> 7 -> 6 -> 4


- 3은 혼자서 팀을 이루고 4, 7, 6은 세명이서 팀을 이룸


- 팀에 속하지 않은 학생은 1, 2, 5 로 3명


- 팀에 속하지 않은 학생수는?


2. 접근방법

- 방법1. 위상정렬

  한 정점에서 나가는 간선은 무조건 1개

  한 정점에 들어오는 간선은 여러개

  

  들어오는 간선의 수를 헤아린 뒤에 한 정점을 방문시 다음 정점으로 들어가는 간선을 하나씩 없앰

  사이클을 형성할려면 무조건 들어오는 간선이 하나는 존재 하므로

  모든 정점을 방문하면서 들어가는 간선이 없는 정점을 방문하면 팀이 없는 사람만 골라 낼 수 있음


사이클을 형성하지 않는 노드만 방문하여 갯수를 헤아림

노드를 방문하는 조건은 해당 노드로 들어오는 간선이 없으면 사이클을 형성하지 않는다는 의미이므로 간선이 없을 때 방문

for문으로 노드 1부터 노드 n까지 방문


아.. 음 그림이 좀 잘못됬는데 노드 5에서 노드 3으로 들어가는 화살표 방향이 되어야함.


<fig 1>

초기 해당 노드로 들어오는 간선의 수 초기화

노드 1은 들어오는 간선의 수가 1 이므로 방문하지 않음


<fig 2>

노드 2는 들어오는 간선의 수가 없으므로 첫번째로 방문하게 됨


<fig 3>

노드 2를 방문하면서 노드 1로 이어지는 간선을 없애면 노드 1은 방문 가능한 상태가 되어 방문 하게 됨

노드 1을 방문하면서 노드 3으로 들어가는 간선의 수를 하나 없애도 노드 3은 들어오는 간선의 수가 2이므로 방문하지 않음


<fig 4>

노드 4, 노드 7, 노드 6은 들어오는 간선의 수가 1이므로 방문하지 않음


<fig 5>

노드 5는 들어오는 간선의 수가 0이므로 방문

노드 5를 방문하면서 노드 3으로 들어가는 간선의 수를 하나 없애도 노드 3은 간선의 수가 1 이므로 방문하지 않음

실제로 코드는 노드 4를 확인한 다음 노드 5를 확인함(for문 이므로)



- 방법2. stack

  현재까지 방문한 정점을 stack에 쌓은다음 방문했던 정점을 방문했을 때 스택의 어는 부분에 있는지 확인하여 사이클이 아닌 노드의 갯수를 합침

  check[n]은 방문을 나타내며 0은 방문 하지 않음

                                      1은 방문했지만 아직 팀은 아님

                                      2는 팀에 속함

  check[n]이 1인경우 사이클을 이루는 경우와 이루지 않는 경우로 나눌 수 있는데

  stack을 돌려보고 해당 정점이 스택에 없으면 사이클이 없는 것이므로 현재까지 방문했던 노드갯수를 합침


<fig 5>

노드 1을 방문하고 stack에는 1, check[1] = 1


<fig 6>

노드 3을 방문하고 stack에는 3, check[3] = 1


<fig 7>

노드 3은 다시 노드 3을 방문 즉, check[3] = 1 stack을 돌면서 노드 3이 있는지 확인 후 check[3] = 2


<fig 8>

노드 2를 방문 stack에는 2, check[2] = 1

노드 1이 check[1] = 1인 상태이지만 스택에 없기 때문에 현재까지 방문했던 노드 2를 팀을 이루지 않는 인원에 합산


<fig 9>

노드 4, 7, 6을 순서대로 방문 stack 4, 7, 8, check[4] = check[7] = check[6] = 1


<fig 10>

노드 6의 다음 노드는 노드 4 노드 4는 check[4] = 1이므로 노드 4가 스택에 있는지 확인 후 해당 노드 4 부터 노트 6까지 check[n] = 2로 변경

stack에 8이 아니라 6


<fig 11>

노드 5를 방문 stack 5, check[5] = 1

노드 5의 다음 노드는 노드 3 노드 3은 check[3] = 2이므로 현재까지 방문했던 노드 5를 팀에 속하지 않는 인원에 합산



- 방법3. 1 : 1대응 그래프 특성

  방문하는 노드에 방문 순서를 매김

  한 컴포넌트에서 처음 방문한 노드의 숫자가 한번 방문했던 노드를 다시 방문한 노드의 숫자 보다 작거나 같으면 사이클을 형성하고 있음

  팀을 이루고 있는 전체 인원을 합산하여 전체 학생 수에서 팀 인원을 제외


  check[n]을 노드 n의 방문 순서,

  student[n]을 친구간 연결이라 한다면

  

  if(check[student[now] >= check[start]) team += cnt - check[student[now]] + 1

  ans = n - team


<fig 12>

최초에 모든 노드는 방문한 적이 없으므로 check[n] = 0

cnt = 1

노드 1을 최초 방문 이므로 check[1] = 1


<fig 13>

cnt = 2

노드 3은 노드 1 다음 방문이므로 2번째 check[2] = 2

check[노드 3] = 2

check[1] = 1 이므로

team += 2 - 2 + 1 = 1


<fig 14>

cnt = 3

check[노드 2] = 3

check[노드 1] = 1 이므로 앞므로 방문할 노드 1의 check[노드 1]의 값이 더 작음


<fig 15>

cnt = 4

check[노드 4] = 4

check[노드 7] = 5

check[노드 6] = 6


노드 6은 노드 4를 재 방문

check[노드 6] = 6

check[컴포넌트 시작점 즉, 노드 4] = 4

team = 6 - 4 + 1 = 3


<fig 16>

cnt = 7

check[노드 5] = 7


노드 5는 노드 3을 재방문

check[노드 5] = 7

check[노드 3] = 2


3. 시간복잡도

- 방법 1. O(n)


- 방법 2. O(2n)


- 방법 3. O(n)


4. 회고

- 음 첫번째꺼는 인터넷에서 줍줍


- 두번째는 스스로 고민


- 세번째는 맞춘 후에 맞은사람 꺼 봄


- 세번째 방법같은 생각은 어떻게 하지...



소스코드 : 방법 1


소스코드 : 방법 2


소스코드 : 방법 3



[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 4963 섬의 개수  (0) 2018.02.08
BOJ 14890 경사로  (0) 2018.02.07
BOJ 14891 톱니바퀴  (0) 2018.02.05
BOJ 2331 반복수열  (0) 2018.01.30
BOJ 10451 순열 사이클  (0) 2018.01.30

+ Recent posts