백준 2610번 (회의준비, C++) [BAEKJOON]

회의준비

https://www.acmicpc.net/problem/2610

시간 제한메모리 제한제출정답맞힌 사람정답 비율
1 초128 MB75752180164028.616%

문제

KOI 준비를 위해 회의를 개최하려 한다.

주최측에서는 회의에 참석하는 사람의 수와 참석자들 사이의 관계를 따져 하나 이상의 위원회를 구성하려고 한다.

위원회를 구성하는 방식은 다음과 같다.

1. 서로 알고 있는 사람은 반드시 같은 위원회에 속해야 한다.

2. 효율적인 회의 진행을 위해 위원회의 수는 최대가 되어야 한다.

이런 방식으로 위원회를 구성한 후에 각 위원회의 대표를 한 명씩 뽑아야 한다.

각 위원회의 대표만이 회의 시간 중 발언권을 가지며,

따라서 회의 참석자들이 자신의 의견을 말하기 위해서는 자신이 속한 위원회의 대표에게 자신의 의견을 전달해야 한다.

그런데 각 참석자는 자신이 알고 있는 사람에게만 의견을 전달할 수 있어 대표에게 의견을 전달하기 위해서는 때로 여러 사람을 거쳐야 한다.

대표에게 의견을 전달하는 경로가 여러 개 있을 경우에는 가장 적은 사람을 거치는 경로로 의견을 전달하며

이때 거치는 사람의 수를 참석자의 의사전달시간이라고 한다.

위원회에서 모든 참석자들의 의사전달시간 중 최댓값이 최소가 되도록 대표를 정하는 프로그램을 작성하시오.

예를 들어 1번, 2번, 3번 세 사람으로 구성되어 있는 위원회에서 1번과 2번, 2번과 3번이 서로 알고 있다고 하자.

1번이 대표가 되면 3번이 대표인 1번에게 의견을 전달하기 위해서 2번을 거쳐야만 한다.

반대로 3번이 대표가 되어도 1번이 대표인 3번에게 의견을 전달하려면 2번을 거쳐야만 한다.

하지만 2번이 대표가 되면 1번과 3번 둘 다 아무도 거치지 않고 대표에게 직접 의견을 전달 할 수 있다.

따라서 이와 같은 경우 2번이 대표가 되어야 한다.

입력

첫째 중에 회의에 참석하는 사람의 수 N이 주어진다.

참석자들은 1부터 N까지의 자연수로 표현되며 회의에 참석하는 인원은 100 이하이다.

둘째 줄에는 서로 알고 있는 관계의 수 M이 주어진다.

이어 M개의 각 줄에는 서로 아는 사이인 참석자를 나타내는 두개의 자연수가 주어진다.

출력

첫째 줄에는 구성되는 위원회의 수 K를 출력한다.

다음 K줄에는 각 위원회의 대표 번호를 작은 수부터 차례로 한 줄에 하나씩 출력한다.

한 위원회의 대표가 될 수 있는 사람이 둘 이상일 경우 그중 한 명만 출력하면 된다.

예제 입력 1

8
7
1 2
2 3
4 5
5 6
4 6
6 7
7 4

예제 출력 1

3
2
4
8

추가 반례

예제 입력 A

100
0

예제 출력 A

100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

예제 입력 B

9
8
1 2
2 3
3 4
4 5
4 6
4 7
4 8
4 9

예제 출력 B

1
3

예제 입력 C

5
4
5 1
1 2
2 3
3 4

예제 출력 C

1
2

출처

Olympiad > 한국정보올림피아드 > 한국정보올림피아드시․도지역본선 > 본선 2004 > 중등부 3번

Olympiad > 한국정보올림피아드 > 한국정보올림피아드시․도지역본선 > 지역선 2004 > 고등부 3번

  • 데이터를 추가한 사람: eightco
  • 문제의 오타를 찾은 사람: sky1357

알고리즘 분류


통과된 코드

Floyd-Warshall 알고리즘을 이용하여 의사전달 시간의 최솟값을 구한다.

그 후에 Union-Find를 이용하여 위원회의 개수와 대표를 구하면 된다.

(분리 집합 + 플로이드 와샬 문제)

#include <iostream>
#include <vector>
#include <set>

using namespace std;

// N : 참석하는 사람
int N, K, f, b;

constexpr int INF = INT32_MAX/2;

constexpr int MAX = 101;

vector<pair<int, int>> graph[MAX];

int disArr[MAX][MAX];

int sumArr[MAX];

// 유니온 root노드 배열
int uArr[MAX];

set<int> checkSet;

//부모를 찾는 함수
//모든 경로가 부모를 가르키게 함
//상수 시간의 복잡도
int Find(int x)
{
	if (uArr[x] == x) return x;
	else return uArr[x] = Find(uArr[x]);
}

//두 노드를 연결 시키는 것
//기준을 정해서 연결시키는 것이 헷갈리지 않음
//작은쪽이 부모 or 큰쪽이 부모
void Union(int x, int y)
{
	x = Find(x);
	y = Find(y);
	if (x != y) {
		if (sumArr[x] <= sumArr[y]) uArr[y] = x;
		else uArr[x] = y;
	}
}

int main()
{
	ios_base::sync_with_stdio(false); // scanf와 동기화를 비활성화
	// cin.tie(null); 코드는 cin과 cout의 묶음을 풀어줍니다.
	cin.tie(NULL);
	cout.tie(NULL);

	cin >> N >> K;

	// 유니온 배열 초기화
	for (int i = 1; i <= N; i++) uArr[i] = i;

	// 서로를 알고 있음(양방향)
	for (int i = 0; i < K; i++) {
		cin >> f >> b;
		graph[f].push_back(make_pair(b, 1));
		graph[b].push_back(make_pair(f, 1));
	}

	// 최단 거리 배열 disArr 배열을 INF 초기화
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			disArr[i][j] = INF;
		}
	}

	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < graph[i].size(); j++) {
			int v = graph[i][j].first;
			int weight = graph[i][j].second;
			disArr[i][v] = weight;
		}
	}

	// Floyd-Warshall 알고리즘
	for (int k = 1; k <= N; k++) {
		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= N; j++) {
				if (i == j) disArr[i][j] = 0;
				else disArr[i][j] = min(disArr[i][j], disArr[i][k] + disArr[k][j]);
			}
		}
	}

	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			
			if (disArr[i][j] == INF) continue;
			// 의사전달시간 중 최대값이 최소가 되도록 대표를 선출
			sumArr[i] = max(sumArr[i], disArr[i][j]); 
		}
	}

	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < graph[i].size(); j++) {
			// Union Find를 사용하여 위원회를 구성
			Union(i, graph[i][j].first);
		}
	}

	// 결과를 출력
	// Set을 이용하여 위원회의 개수와 대표를 저장
	for (int i = 1; i <= N; i++) checkSet.insert(Find(i));
	
	cout << checkSet.size() << "\n";
	for (auto& it : checkSet) cout << it << "\n";

	return 0;
}

“백준 2610번 (회의준비, C++) [BAEKJOON]”에 대한 1개의 생각

  1. 핑백: 알고리즘 – 유니온 파인드(Union find) & 서로소 집합(Disjoint Set) - 어제와 내일의 나 그 사이의 이야기

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤