문제출처 : 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

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


1. 문제요약

- 8개의 톱니를 가진 4개의 톱니바퀴

- 특정 하나의 톱니바퀴를 시계, 반시계 방향으로 회전

- 마주보고 있는 톱니의 극이 반대이면 옆 톱니바퀴도 같이 회전함


2. 접근방법

- 시뮬레이션


3. 시간복잡도


4. 회고

- 시뮬레이션이 제일 귀찮아


- 톱니 회전을 재귀로 구현했는데... 현재 톱니바퀴를 굴리기 전에 좌우 살펴서 돌릴 수 있으면 재귀

  재귀가 끝난 뒤 현재 톱니바퀴 회전

  재귀가 무한루프에 빠지지 않도록 톱니바퀴에 check를 넣어서 돌린적이 있는지 없는지 확인

  이런식으로 했는데


- for문으로 할 수 있는 방법도 있네

  돌리는 톱니바퀴가 결정되면 좌우에 있는 톱니바퀴는 어디로 돌릴지 방향에 대한 정보를 dir[4]에 각각 저장

  톱니바퀴 4개를 돌면서 저장된 방향대로 톱니바퀴를 회전



소스코드


소스코드 : for문



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

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

BOJ 14890 경사로  (0) 2018.02.07
BOJ 9466 텀 프로젝트  (0) 2018.02.06
BOJ 2331 반복수열  (0) 2018.01.30
BOJ 10451 순열 사이클  (0) 2018.01.30
BOJ 1707 이분 그래프  (0) 2018.01.29

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


1. 문제요약

- D[1] = A

  D[n] = D[n-1]의 각 자릿수의 숫자를 P번 곱한 수들의 합


- A = 57, P = 2일 때,

  {57, 74(5^2 + 7^2 = 25 + 49), 65, 61, 37, 58, 89, 145, 42, 20, 4, 16, 37, ...}

  여기서 {57, 74, 65, 61}을 제외한 숫자는  반복된다.


- 1 <= A <= 1,000

- 1 <= P <= 5


- 반복되지 않는 숫자의 개수는?


2. 접근방법

- 두 가지를 생각해 봤는데


1) V[num] = cnt


2) V[cnt] = num


- 1) 방법은 해당 특정 숫자가 몇번째 인지 저장해서 한번 방문했던 숫자를 재 방문하면 해당 cnt를 리턴

      num이 얼마나 커질지 모름....


- 2) 방법은 cnt에 num을 가지고 있음

      배열의 크기는 최대 1000을 넘지 않지만

      해당 숫자가 이전에 있었는지를 연산 후에 매번 확인해줘야함.


3. 시간복잡도

- 1)은 O(N) : 1,000

- 2)는 O(N^2) : 1,000,000


4. 회고

- 난 1)번 방법으로 풀긴했는데 음... 2)번 방법이 좀 더 확실할 것같다. 

  1)번은 배열 크기를 알 수가 없으므로



소스코드 : 1)번 방법



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

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

BOJ 9466 텀 프로젝트  (0) 2018.02.06
BOJ 14891 톱니바퀴  (0) 2018.02.05
BOJ 10451 순열 사이클  (0) 2018.01.30
BOJ 1707 이분 그래프  (0) 2018.01.29
BOJ 11724 연결 요소의 개수  (0) 2018.01.26

+ Recent posts