PS/DFS, BFS

[1707] 이분 그래프

프레딕 2023. 6. 13. 22:37
728x90

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

 

1707번: 이분 그래프

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V와 간선의 개수 E가 빈 칸을 사이에

www.acmicpc.net

문제

그래프의 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로 인접하지 않도록 분할할 수 있을 때, 그러한 그래프를 특별히 이분 그래프 (Bipartite Graph) 라 부른다.

그래프가 입력으로 주어졌을 때, 이 그래프가 이분 그래프인지 아닌지 판별하는 프로그램을 작성하시오.

입력

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V와 간선의 개수 E가 빈 칸을 사이에 두고 순서대로 주어진다. 각 정점에는 1부터 V까지 차례로 번호가 붙어 있다. 이어서 둘째 줄부터 E개의 줄에 걸쳐 간선에 대한 정보가 주어지는데, 각 줄에 인접한 두 정점의 번호 u, v (u ≠ v)가 빈 칸을 사이에 두고 주어진다. 

출력

K개의 줄에 걸쳐 입력으로 주어진 그래프가 이분 그래프이면 YES, 아니면 NO를 순서대로 출력한다.

코드

#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>

using namespace std;

int K;
int V, E;

vector<vector<int>> adj;
vector<bool> a;
vector<bool> visited; // 정점의 간선 수

// group이 true 면은 a, false면 b
void dfs(int start, bool group){
	visited[start] = true;
	
	for(int i=0; i<adj[start].size(); ++i){
		int here = adj[start][i];

		if(visited[here]){
			continue;
		}
		
		if(group){
			a[here] = false;
		}

		else{
			a[here] = true;
		}

		dfs(here, !group);
	}
}

void clearAll(){
	adj.clear();
	adj.resize(V+1);

	a = vector<bool>(adj.size(), false);
	visited = vector<bool>(adj.size(), false);
}

bool checkAns(){
	for(int i=1; i<V+1; ++i){
		for(int j=0; j<adj[i].size(); ++j){
			if(a[i] == a[adj[i][j]]){
				return false;
			}
		}
	}
	return true;
}

int main(void){

	cin >> K;

	for(int i=0; i<K; ++i){
		cin >> V >> E;
		clearAll();
		
		for(int j=0; j<E; ++j){
			int x, y;
			cin >> x >> y;
			adj[x].push_back(y);
			adj[y].push_back(x);
		}

		for(int t = 1; t<V+1; ++t){
			if(!visited[t]){
				a[t] = true;
				dfs(t, true);
			}
		}

		if(checkAns()){
			cout << "YES" << '\n';
		}
		else{
			cout << "NO" << '\n';
		}
	}

	return 0;
}

dfs로 풀어주었다.

먼저, 첫 번째 정점의 그룹을 true로 잡고 dfs를 돌려 다음번의 정점을 false로 하고... 이걸 반복해준다.

혹시 끊어진 정점이 있을 수 있으니 모든 정점을 출발점으로 해서 dfs를 해준다. (단, 방문된 정점은 제외)

그 다음, checkAns에서 인접하게 연결된 경로의 정점인데 그룹이 같으면 false를 return하고 이외엔 true를 return한다.

반환된 값에 따라 답을 나눠주면 끝이다.

728x90
반응형