728x90

문제

지민이는 파티에 가서 이야기 하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게 과장해서 말한다. 당연히 과장해서 이야기하는 것이 훨씬 더 재미있기 때문에, 되도록이면 과장해서 이야기하려고 한다. 하지만, 지민이는 거짓말쟁이로 알려지기는 싫어한다. 문제는 몇몇 사람들은 그 이야기의 진실을 안다는 것이다. 따라서 이런 사람들이 파티에 왔을 때는, 지민이는 진실을 이야기할 수 밖에 없다. 당연히, 어떤 사람이 어떤 파티에서는 진실을 듣고, 또다른 파티에서는 과장된 이야기를 들었을 때도 지민이는 거짓말쟁이로 알려지게 된다. 지민이는 이런 일을 모두 피해야 한다.

사람의 수 N이 주어진다. 그리고 그 이야기의 진실을 아는 사람이 주어진다. 그리고 각 파티에 오는 사람들의 번호가 주어진다. 지민이는 모든 파티에 참가해야 한다. 이때, 지민이가 거짓말쟁이로 알려지지 않으면서, 과장된 이야기를 할 수 있는 파티 개수의 최댓값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 사람의 수 N과 파티의 수 M이 주어진다.

둘째 줄에는 이야기의 진실을 아는 사람의 수와 번호가 주어진다. 진실을 아는 사람의 수가 먼저 주어지고 그 개수만큼 사람들의 번호가 주어진다. 사람들의 번호는 1부터 N까지의 수로 주어진다.

셋째 줄부터 M개의 줄에는 각 파티마다 오는 사람의 수와 번호가 같은 방식으로 주어진다.

N, M은 50 이하의 자연수이고, 진실을 아는 사람의 수와 각 파티마다 오는 사람의 수는 모두 0 이상 50 이하의 정수이다.

출력

첫째 줄에 문제의 정답을 출력한다.

예제 입력 1 복사

4 3 0 2 1 2 1 3 3 2 3 4

예제 출력 1 복사

3


예제가 너무 안 좋아서 문제 이해해 도움이 안 되는 문제였다.

내가 예제를 만들자면

4 3 

1 1

2 1 2

1 2

2 3 4

이 예제의 답은 1이다. 첫번째 파티에서 1번 사람과 2번 사람이 만나기 때문에 두번재 파티에서 2는 진실을 알 수 있기 때문에 1, 2번사람과 연관이 없는 마지막 파티의 3, 4번 사람에게만 과장을 할 수 있다.

이 예제만 이해해도 문제 이해에 크게 도움이 된다.

 

문제 해결을 위해서 union-find를 사용했다.

같은 파티에 참여한 사람을 모두 같은 parent로 묶어서 그 안에 진실을 아는 자가 포함되었는지 여부를 판별한다. 

 

코드 원본 : https://github.com/chosh95/STUDY/blob/master/BaekJoon/2020/%EA%B1%B0%EC%A7%93%EB%A7%90%20(1043%EB%B2%88).cpp

 

chosh95/STUDY

프로그래밍 문제 및 알고리즘 정리. Contribute to chosh95/STUDY development by creating an account on GitHub.

github.com

 

C++ 코드

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N, M, T, res;
vector<int> truth; // 진실을 아는 사람들
vector<int> party[51]; // i번 파티에 참여하는 사람 모임
int parent[51]; // i번 사람의 부모

int find(int u) {
	if (parent[u] == u) return u;
	return parent[u] = find(parent[u]);
}

void Union(int u, int v) {
	u = find(u);
	v = find(v);
	parent[v] = u;
}

int main()
{
	cin >> N >> M;
	cin >> T;
	for (int tmp, i = 1; i <= T; i++) {
		cin >> tmp;
		truth.push_back(tmp);
	}
		
	for (int cnt, i = 1; i <= M; i++) {
		cin >> cnt;
		for (int tmp, j = 1; j <= cnt; j++) {
			cin >> tmp;
			party[i].push_back(tmp);
		}
	}

	for (int i = 1; i <= N; i++) parent[i] = i; //parent 초기화

	for (int i = 1; i <= M; i++) { // 각 파티에 참여한 사람끼리 묶는다.
		int cur = party[i][0];
		for (int j = 1; j < party[i].size(); j++) 
			Union(cur, party[i][j]);
	}

	for (int i = 1; i <= M; i++) { // 각 파티에서 진실을 아는 사람과 묶여있다면 과장할 수 없다.
		bool isPossible = true;
		int cur = party[i][0];
		for (int j = 0; j < truth.size(); j++) {
			if (find(cur) == find(truth[j])) {
				isPossible = false;
				break;
			}
		}
		if (isPossible) res++;
	}
	cout << res;
}
728x90

'알고리즘 > 백준' 카테고리의 다른 글

[백준] N과 M (9) (15663번)  (0) 2020.07.04
[백준] N과 M (8) (15657번)  (0) 2020.07.04
[백준] 트리의 순회 (2263번)  (0) 2020.07.03
[백준] 파티 (1238번)  (0) 2020.07.02
[백준] 특정한 최단 경로 (1504번)  (0) 2020.07.01

+ Recent posts