알고리즘 및 자료구조/그래프

C++ 백준 1043 거짓말

Sh_Blog 2024. 4. 2. 14:10

백준 1043

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

 

1043번: 거짓말

지민이는 파티에 가서 이야기 하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게

www.acmicpc.net

풀이 전 나의 생각

이야기의 진실을 알고 있는 사람과 각 파티의 사람 정보가 주어질 때

지민이가 과장되게 말할 수 있는 파티의 수를 구해야 한다.

 

조건

- N, M은 50 이하의 자연수

- 진실을 아는 사람의 수는 0 이상 50 이하의 정수

- 파티마다 오는 사람의 수는 1 이상 50 이하의 정수

 

과정

진실을 알고 있는 사람이 3이고 파티에 같이있는 사람이 4라면

4는 이야기가 진실이라는 것을 알 수 있다. 그럼 4도 다른 파티장에

갔을 때, 4와 같이 있는 파티 사람에게 이야기의 진실을 알려줄 수 있다.

 

이러한 형태를 보면 그래프의 형태가 나오게 되는데 이야기의 진실을

알고 있는 사람으로부터 연결 되어있는 모든 사람이 저장된 그래프를 탐색하며

진실을 알게된 사람을 모두 체크해주면된다.

 

사실 이 문제는 그래프보다 유니온 파인드를 이용하여 부모를 기준으로

그룹을 합병하는 것이 훨씬 간단하고 풀기쉽다.

 

하지만 그래프로 푸는 방법을 알고있다면 유니온 파인드의 내용이 갑자기

기억이 안날 때 유용할 것 같아서 DFS와 그래프를 이용하여 풀이를 진행했다.

 

과정은 다음과 같다.

1. 각 파티에 있는 사람, 진실을 알고 있는 사람, 각 파티에 있는 모든 사람을 연결한 그래프 저장

2. 진실을 알고있는 사람들의 DFS 탐색을 진행하며 연결된 모든 사람을 따로 체크

3. 각 파티에 있는 사람을 체크하면서 진실을 알고 있는지, 아닌지 체크

풀이

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <string>
#include <queue>
#include <string.h>
#include <limits.h>
#include <cstdio>
#include <map>

using namespace std;

vector<vector<int>>link(51);
vector<vector<int>>input(51);

bool visited[51];
bool true_v[51];

void dfs(int st)
{
	visited[st] = true;
	true_v[st] = true;
	for (int next : link[st])
	{
		if (!visited[next])
		{
			dfs(next);
		}
	}
}

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

	vector<int>true_p;
	int N, M, T;

	cin >> N >> M >> T;

	int ans = M;

	if (T != 0)
	{
		for (int i = 0; i < T; i++)
		{
			int u;
			cin >> u;

			//진실을 알고 있는 사람 저장
			true_p.push_back(u); 
		}
	}

	for (int i = 0; i < M; i++)
	{
		int n = 0, prev = 0;
		cin >> n;

		for (int j = 0; j < n; j++)
		{
			int h;
			cin >> h;

			//각 파티에 있는 사람 저장
			input[i].push_back(h);

			if (j == 0)
			{
				prev = h;
			}
			else
			{
				//모든 파티에 있는 사람의 관계 저장
				link[prev].push_back(h);
				link[h].push_back(prev);
				prev = h;
			}
		}
	}

	if (T != 0)
	{
		for (int val : true_p)
		{
			//진실을 알고 있는 사람과 관련된 사람을 체크하기 위해 DFS 탐색 진행
			fill(visited, visited + 51, false);
			dfs(val);
		}

		//각 파티의 사람들이 진실을 알고 있는지, 아닌지 체크
		for (int i = 0; i < M; i++)
		{
			for (int val : input[i])
			{
				if (true_v[val])
				{
					ans--;
					break;
				}
			}
		}

		cout << ans;
	}
	else
	{
		cout << ans;
	}
}