[백준 1043] 거짓말 (C++)

codingNoob12·2024년 3월 7일
0

알고리즘

목록 보기
21/73

이 문제를 처음 봤을 때는 그냥 각 파티에 진실을 아는 사람이 존재하는지만 체크하는 문제인 줄 알았다. 하지만, 문제를 잘 읽어보면 진실을 아는 사람들이 있는 파티에서는 진실을 이야기 한다고 한다. 이는 해당 파티에 참석했던 사람들이 진실을 알게 된다는 의미이다. 따라서, 진실을 알고 있는 사람이 파티가 열릴 때 마다, 진실을 아는 사람이 추가될 수 있는 상황인 것이다.

그렇다면, 누가 진실을 알게 될 수 있는지를 표시해줘야한다.
먼저, 같은 파티를 참석한 사람들은 서로 들은 이야기를 공유할 수 있다고 가정하자. 이로 인해, 진실을 알고 있는 사람이 파티에 있다면 서로 들은 이야기가 다르므로 지민이가 거짓말쟁이로 소문나게 되는 것이라고 하자.

따라서, 이야기를 공유할 수 있는 관계에 진실을 아는 사람이 존재한다면, 해당 관계에 속한 사람들은 모두 진실을 안다고 할 수 있다.

그렇기에, 먼저 이야기를 공유할 수 있는 관계를 자료구조로 표현해야하는데, 이는 그래프로 쉽게 표현이 가능하다.

이후, BFS나 DFS등의 그래프 탐색 기법들을 이용해서 진실을 아는 사람들을 시작점으로 탐색해나가면 진실을 아는 사람들을 파악할 수 있다.

마지막으로, 파티에 진실을 아는 사람이 참석했는지 체크하면 지민이가 과장할 수 있는지를 판별할 수 있게 된다.

#include <bits/stdc++.h>
using namespace std;

int n, m, k;
set<int> adj[51]; // 이야기를 공유할 수 있는 관계를 그래프로 표현.
vector<int> fact, party[50];
bool vis[51];

void bfs() { // 이야기 공유가능한 관계를 bfs로 탐색
	queue<int> q;

	for (int f : fact) { // 탐색의 시작점을 진실을 아는 사람들로 설정
		q.push(f);
		vis[f] = 1;
	}

	while (!q.empty()) {
		int cur = q.front();
		q.pop();

		for (int nxt : adj[cur]) {
			if (vis[nxt]) continue;
			q.push(nxt);
			vis[nxt] = 1; // 방문을 했다면 진실을 아는 사람
		}
	}
}

bool exaggerate(int i) { // 파티에서 과장해서 이야기 할 수 있는지 확인
	for (int p : party[i]) {
		if (vis[p]) return 0;
	}
	return 1;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> k;
	while (k--) {
		int x;
		cin >> x;
		fact.push_back(x);
	}

	for (int i = 0; i < m; i++) {
		cin >> k;
		for (int j = 0; j < k; j++) {
			int x;
			cin >> x;
			party[i].push_back(x);
		}

		for (int idx1 = 0; idx1 < k; idx1++) {
			for (int idx2 = 0; idx2 < k; idx2++) {
				if (idx1 == idx2) continue;
				int u = party[i][idx1], v = party[i][idx2];
				adj[u].insert(v);
				adj[v].insert(u);
			}
		}
	}

	bfs();

	int ans = 0;
	for (int i = 0; i < m; i++) {
		if (exaggerate(i)) ans++;
	}
	cout << ans;
}
profile
나는감자

0개의 댓글