https://www.acmicpc.net/problem/1707
정답률 24.408%
그래프의 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로 인접하지 않도록 분할할 수 있을 때, 그러한 그래프를 특별히 이분 그래프 (Bipartite Graph) 라 부른다.
그래프가 입력으로 주어졌을 때, 이 그래프가 이분 그래프인지 아닌지 판별하는 프로그램을 작성하시오.
2
3 2
1 3
2 3
4 4
1 2
2 3
3 4
4 2
YES
NO
우선 이분 그래프에 대해서 개념적으로 알아보면 인접한 정점끼리 서로 다른 색을 칠했을 때 모든 정점을 두 가지 색으로 칠할 수 있는 그래프이다. 다음 그림에서 왼쪽이 이분 그래프에 해당한다.
그래프의 모든 정점이 이어져 있지 않은 경우도 있기 때문에 BFS나 DFS를 이용해서 모든 정점을 탐색하며 인접 노드들 색칠해간다.
isBipartite = true;
color = new Integer[V + 1];
//모든 정점에 대해 탐색
for (int i = 1; i <= V; i++) {
//이분 그래프가 아닐 시 탐색 중지
if (isBipartite) {
bfs(i);
} else {
break;
}
}
인접 노드를 탐색여부를 Integer 배열으로 구분한다. null일 경우 색칠되지 않은 (방문하지 않은) 상태이고 0과 1로 구분하여 노드를 색칠한다.
//인접 노드가 색칠되지 않았을 경우
if (color[adjNode] == null) {
//현재 노드와 다른 색으로 색칠
color[adjNode] = 1 - color[curNode];
queue.add(adjNode);
}
//인접 노드와 현재 노드가 같은 색일 경우 이분 그래프가 아님
else if (color[adjNode].equals(color[curNode])) {
isBipartite = false;
}
정점이 인접 노드가 존재하지 않을 수도 있으므로 탐색을 수행하기 전 시작 노드에 색칠을 해준다.
//색칠되지 않은 정점일 경우 색칠
if (color[start] == null) {
color[start] = 1;
}
//백준
public class Main {
static List<List<Integer>> adjList = new ArrayList<>();
static Integer[] color; //각 노드의 색칠 정보
static boolean isBipartite; //이분 그래프 여부
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("src/input.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int K = Integer.parseInt(br.readLine()); //테스트 케이스
for (int testCase = 0; testCase < K; testCase++) {
st = new StringTokenizer(br.readLine());
int V = Integer.parseInt(st.nextToken()); //정점의 개수
int E = Integer.parseInt(st.nextToken()); //간선의 개수
adjList = new ArrayList<>();
for (int i = 0; i <= V; i++) {
adjList.add(new ArrayList<>());
}
//인접 리스트 생성
for (int i = 0; i < E; i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
adjList.get(a).add(b);
adjList.get(b).add(a);
}
isBipartite = true;
color = new Integer[V + 1];
//모든 정점에 대해 탐색
for (int i = 1; i <= V; i++) {
//이분 그래프가 아닐 시 탐색 중지
if (isBipartite) {
bfs(i);
//dfs(i);
} else {
break;
}
}
System.out.println(isBipartite ? "YES" : "NO");
}
}
//너비 우선 탐색
static void bfs(int start) {
Queue<Integer> queue = new LinkedList<>();
queue.add(start);
//색칠되지 않은 정점일 경우 색칠
if (color[start] == null) {
color[start] = 1;
}
while (!queue.isEmpty()) {
int curNode = queue.poll();
//인접 노드 탐색
for (Integer adjNode : adjList.get(curNode)) {
//인접 노드가 색칠되지 않았을 경우
if (color[adjNode] == null) {
//현재 노드와 다른 색으로 색칠
color[adjNode] = 1 - color[curNode];
queue.add(adjNode);
}
//인접 노드와 현재 노드가 같은 색일 경우 이분 그래프가 아님
else if (color[adjNode].equals(color[curNode])) {
isBipartite = false;
}
}
}
}
//깊이 우선 탐색
static void dfs(int curNode) {
if (color[curNode] == null) {
color[curNode] = 1;
}
for (Integer adjNode : adjList.get(curNode)) {
if (color[adjNode] == null) {
color[adjNode] = 1 - color[curNode];
dfs(adjNode);
} else if (color[adjNode].equals(color[curNode])) {
isBipartite = false;
}
}
}
}