본문 바로가기
알고리즘 문제풀이/백준

[백준 9466] 텀 프로젝트

by m2162003 2020. 12. 3.

www.acmicpc.net/problem/9466

 

9466번: 텀 프로젝트

이번 가을학기에 '문제 해결' 강의를 신청한 학생들은 텀 프로젝트를 수행해야 한다. 프로젝트 팀원 수에는 제한이 없다. 심지어 모든 학생들이 동일한 팀의 팀원인 경우와 같이 한 팀만 있을

www.acmicpc.net

directed graph에서 cycle detection 응용문제이다.

사이클에 해당하지 않는 노드를 찾는 문제로 dfs를 사용하거나 indegree + 위상정렬을 사용한다.

 

1. dfs를 사용할 때

사이클이 있는지 확인할 때 지나간지 여부를 체크하는 배열 path와

확인이 끝났다는 표식인 done 배열 두 가지를 사용한다.

 

1부터 n까지 done이 아니라면 dfs에 들어가는데

dfs에 들어가서 방문 체크path를 한다. 그 다음 노드가 방문 체크되지 않았다면 dfs를 다시 시작한다.

만약 다음 노드가 이미 방문한 노드라면 사이클이 존재한다는 의미이다. 

이미 체크가 끝난 노드가 아니라면 사이클을 시작해서 사이클 내의 노드가 몇개인지 세준다.

 

중간이 path[j]이든 done[j]이든 상관없다.

#include <stdio.h>
#include <string.h>

using namespace std;

const int MAX = 100000 + 1;
int t, n, cnt;
int arr[MAX];
bool path[MAX];
bool done[MAX];

void DFS(int node)
{
  path[node] = true;

  int nextNode = arr[node];

  if (!path[nextNode])
  {
    DFS(nextNode);
  }
  else if (!done[nextNode])
  {
    for (int i = nextNode; i != node; i = arr[i])
    {
      cnt++;
    }
    cnt++;
  }
  done[node] = true;
}
int main(void)
{
  scanf("%d", &t);
  for (int i = 0; i < t; i++)
  {
    scanf("%d", &n);
    cnt = 0;
    memset(done, false, sizeof(bool) * (n + 1));
    memset(path, false, sizeof(bool) * (n + 1));
    for (int j = 1; j <= n; j++)
    {
      scanf("%d", &arr[j]);
    }

    for (int j = 1; j <= n; j++)
    {
      if (!path[j]) // if(!visited[j])
        DFS(j);
    }

    printf("%d\n", n - cnt);
  }

  return 0;
}

 

2. indegree와 위상정렬

사이클이 있다는 건 indegree와 outdegree가 모두 1이상이라는 의미이다.

따라서 indegree가 없는 친구들을 세줄 예정이다.

 

indegree를 전부 카운트한 다음에

 

dfs

이미 방문한 적 없거나 indegree= 0 이라면 카운트하고 해당 노드를 방문한다.

해당 노드와 연결된 노드의 indegree를 --하고 다시 그 노드가 indegree = 0 && not visited라면 dfs를 진행한다.

 

 

#include <stdio.h>
#include <algorithm>

using namespace std;

const int MAX = 100000 + 1;
int t, n, cnt;
int arr[MAX];
int visited[MAX];
int indegree[MAX];

void DFS(int node)
{
  visited[node] = 1;
  cnt++;
  int next = arr[node];
  indegree[next]--;
  if (visited[next] == 0 && indegree[next] == 0)
  {
    DFS(next);
  }
}
int main(void)
{
  scanf("%d", &t);
  for (int i = 0; i < t; i++)
  {
    scanf("%d", &n);
    cnt = 0;
    fill(visited, visited + n + 1, 0);
    fill(indegree, indegree + n + 1, 0);
    for (int j = 1; j <= n; j++)
    {
      scanf("%d", &arr[j]);
      indegree[arr[j]]++;
    }

    for (int j = 1; j <= n; j++)
    {
      if (visited[j] == 0 && indegree[j] == 0)
        DFS(j);
    }

    printf("%d\n", cnt);
  }

  return 0;
}

 

 

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 11967] 불켜기  (0) 2020.12.10
[백준 5427] 불  (0) 2020.12.03
[백준 2493] 탑  (0) 2020.11.30
[백준 6198] 옥상 정원 꾸미기  (0) 2020.11.30
[백준 4889] 안정적인 문자열  (0) 2020.11.29

댓글