코딩뚠뚠

[백준문제풀이] 9466 텀 프로젝트 본문

알고리즘 문제풀이/백준문제풀이

[백준문제풀이] 9466 텀 프로젝트

로디네로 2021. 1. 1. 14:48
반응형

 

풀이일시 : 2020-10-13

 

문제 :

이번 가을학기에 '문제 해결' 강의를 신청한 학생들은 텀 프로젝트를 수행해야 한다. 프로젝트 팀원 수에는 제한이 없다. 심지어 모든 학생들이 동일한 팀의 팀원인 경우와 같이 한 팀만 있을 수도 있다. 프로젝트 팀을 구성하기 위해, 모든 학생들은 프로젝트를 함께하고 싶은 학생을 선택해야 한다. (단, 단 한 명만 선택할 수 있다.) 혼자 하고 싶어하는 학생은 자기 자신을 선택하는 것도 가능하다.

학생들이(s1, s2, ..., sr)이라 할 때, r=1이고 s1이 s1을 선택하는 경우나, s1이 s2를 선택하고, s2가 s3를 선택하고,..., sr-1이 sr을 선택하고, sr이 s1을 선택하는 경우에만 한 팀이 될 수 있다.

예를 들어, 한 반에 7명의 학생이 있다고 하자. 학생들을 1번부터 7번으로 표현할 때, 선택의 결과는 다음과 같다.

1

2

3

4

5

6

7

3

1

3

7

3

4

6

위의 결과를 통해 (3)과 (4, 7, 6)이 팀을 이룰 수 있다. 1, 2, 5는 어느 팀에도 속하지 않는다.

주어진 선택의 결과를 보고 어느 프로젝트 팀에도 속하지 않는 학생들의 수를 계산하는 프로그램을 작성하라.

입력 :

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫 줄에는 학생의 수가 정수 n (2 ≤ n ≤ 100,000)으로 주어진다. 각 테스트 케이스의 둘째 줄에는 선택된 학생들의 번호가 주어진다. (모든 학생들은 1부터 n까지 번호가 부여된다.)

ex)

2

7

3 1 3 7 3 4 6

8

1 2 3 4 5 6 7 8

출력 :

각 테스트 케이스마다 한 줄에 출력하고, 각 줄에는 프로젝트 팀에 속하지 못한 학생들의 수를 나타내면 된다.

ex)

3

0

풀이 :

dfs를 이용하여 인접노드를 탐색하며 풀이할 수 있는데 1->3->2->1 로 부모가 같아야지 한 팀을 이룰 수 있다.

1->3->2 로 끝나버리면 팀을 이룰수없다.

한 번 방문한 것을 visit으로 나타내는데 다른 팀에서 visit한 노드를 원할 수도 있기 때문에 visit 뿐만 아닌 done배열을 사용한다. done은 완전히 팀을 이룬경우에 1이 되는 배열이다. (visit했다고 끝이아님)

 

dbstndi6316.tistory.com/64

 

[기본문제풀이] DFS 깊이우선탐색

풀이일시 : 2020-08-30 ​ DFS : 깊이우선탐색으로 DFS보다 좁고 깊게 탐색해나가며 전체 정점을 탐색하는 방법이다. 주로 stack을 이용한다. 아래그림이 dfs를 한눈에 보여준다고 생각한다 출처 : http://

dbstndi6316.tistory.com

#include <iostream>
#include <cstring> //for memset
#define MAX 100001

using namespace std;

int graph[MAX];
bool visit[MAX];
bool done[MAX]; //더이상 이 노드를 방문하지 않을 것을 확신하는 경우에만 true
int cnt,n;

void dfs(int x) {
	visit[x] = true; //방문처리 해주고
	int next = graph[x]; //x가 가리키는것이 next
	//아예 가리키지 않는다면 끝나버릴것
	if (!visit[next]) { //방문 안했다면 dfs를 돌린다
		dfs(next);
	}
	else if (!done[next]) {	//done이 0이면
		//팀원을 모두 센다
		for (int i = next; i != x; i = graph[i]) { //i!=x 라는것은 자기자신이나올때까지
			cnt++;
		}
		cnt++; //자기자신도 더해준다
	}
	done[x] = true; //x로 시작하는건 더이상 방문하지 않아도 된다는것.
}


int main() {
	int T;
	cin >> T; //테스트케이스 입력
	for (int i = 0; i < T; i++) {
		memset(visit, false, sizeof(visit)); //배열을 초기화
		memset(done, false, sizeof(done)); //배열을 초기화
		cin >> n; //학생의 수

		for (int j = 1; j <= n; j++) { //학생의 수만큼 반복
			cin >> graph[j]; //그래프에 채운다.
		}

		cnt = 0;
		for (int j = 1; j <= n; j++) {
			if (!visit[j]) { //모든 학생노드를 기준으로 visit되지않았다면 dfs돌린다.
				dfs(j);
			}
		}
		cout << n - cnt << endl;
	}
	return 0;
}
반응형