본문 바로가기
백준

[백준] code.plus(그래프 알고리즘,JAVA)16964번, DFS 스페셜 저지

by 열정적인 이찬형 2022. 6. 16.

문제 링크

 

16964번: DFS 스페셜 저지

첫째 줄에 정점의 수 N(2 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N-1개의 줄에는 트리의 간선 정보가 주어진다. 마지막 줄에는 DFS 방문 순서가 주어진다. DFS 방문 순서는 항상 N개의 정수로 이루

www.acmicpc.net


주의사항

  • JAVA를 사용하여 프로그램을 사용하였습니다.
  • 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{ 	
	public static void main(String[] args){
    }
}

문제 설명


 

접근 방법

그래프 알고리즘이란?

각 정점과 연결하는 선분의 정보를 가지고 BFS(너비 우선 탐색), DFS(깊이 우선 탐색) .... 등을 이용하여 정점에서 다른 정점으로 가는 최소값, 최대값 등의 문제에서 출력하라는 결과를 구하는 알고리즘입니다.
 

DFS

DFS(깊이 우선 탐색)은 아래 그림처럼 어떤 조건을 가지고 목표노드에 도달하기까지 자식노드를 통해 이동하며 목표노드까지 도달하는 것을 말합니다.

자식 노드에 도착하면 그 자식노드에서 조건에 만족하는 자식노드로 다시 이동하여 목표 노드로 이동합니다.

 

출처:https://ko.wikipedia.org/wiki/%EA%B9%8A%EC%9D%B4_%EC%9A%B0%EC%84%A0_%ED%83%90%EC%83%89

더 자세한 내용은 아래 링크에 들어가서 확인해주시면 감사하겠습니다.

 

깊이 우선 탐색 - 위키백과, 우리 모두의 백과사전

깊이 우선 탐색의 애니메이션 예시 깊이 우선 탐색( - 優先探索, 영어: depth-first search, DFS)은 맹목적 탐색방법의 하나로 탐색트리의 최근에 첨가된 노드를 선택하고, 이 노드에 적용 가능한 동작

ko.wikipedia.org

 

이 문제에 핵심은

1. 그래프에 대하여 DFS 탐색하는 순서가 올바르면 1, 올바르지 않으면 0을 출력합니다.

2. DFS결과는 여러가지 나올 수 있습니다.

3. 항상 시작 정점은 정점 1입니다.

 

아래와 같은 그래프가 주어졌을 때

정점 1부터 DFS탐색을 진행하면 탐색하는 순서에 따라 지역이 탐색되는 순서가 다릅니다.

만약 루트 1에서 정점 2을 먼저 탐색한다면 정점 4가 먼저 탐색됩니다.

 

 

위 특징을 이용하여 현재 정점에 인접한 정점을 HashSet에 저장한 뒤에 입력받은 순서에 맞게 DFS탐색을 진행하도록 하였습니다.

 

예제입력1

항상 시작 정점은 1이기 때문에 1부터 탐색합니다.

입력된 순서 : 1, 2, 3, 4

1을 탐색으로 1 제거

 

HashSet : 2

입력된 순서 : 2, 3, 4

2 탐색으로 제거

HashSet : 4

입력된 순서 : 3, 4

3은 HashSet에 존재하지 않기 때문에 DFS 탐색으로 불가능!

 

탐색 종료 후 결과 0 출력

 

 

  • BufferedReader를 사용하여 입력 값을 받았습니다.
  • StringTokenizer을 이용하여 그래프의 값을 저장하였습니다.
  • 입력한 순서에 따라 DFS탐색이 가능한지 확인하는 dfs함수를 실행하였습니다.
  • DFS탐색이 가능하면 1, 가능하지 못하면 0을 BufferedWriter에 저장합니다.
  • BufferedWriter에 저장된 결과값을 출력하였습니다.
  • dfs함수는 HashSet을 이용해서 현재 정점에 인접한 정점을 저장한 뒤 입력된 순서대로 DFS탐색이 되는지 확인한다.

 

import java.io.*;
import java.util.*;

public class Main{
	static int N;
	static ArrayList<ArrayList<Integer>> graph = new ArrayList<>();	//그래프 저장 리스트
	static Queue<Integer> result = new LinkedList<Integer>();	//입력된 순서 저장 큐
	static boolean[] visited;	//정점 방문 여부 확인 배열
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        	//입력값 처리하는 BufferedReader
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        	//결과값 출력하는 BufferedWriter
		StringTokenizer st;
		N = Integer.parseInt(br.readLine());
		visited = new boolean[N+1];
		for(int i=0;i<=N;i++)
			graph.add(new ArrayList<>());
            	//그래프 초기화
		for(int i=0;i<N-1;i++) {
			st = new StringTokenizer(br.readLine()," ");
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			graph.get(a).add(b);
			graph.get(b).add(a);
		}
		st = new StringTokenizer(br.readLine()," ");
        	//입력된 순서 저장
		for(int i=0;i<N;i++)
			result.add(Integer.parseInt(st.nextToken()));
		
		int first = result.poll();	//입력된 순서에 시작 정점 추출
		if(first != 1)	//시작 정점 1이 아닌 경우
			bw.write("0");
		else {
			if(dfs(1, 0))	//DFS 탐색 가능시
				bw.write("1");
			else		//DFS 탐색 불가능시
				bw.write("0");
		}
		bw.flush();		//결과 출력
		bw.close();
		br.close();
	}
    	//입력된 순서로 DFS 탐색 가능한지 확인하는 함수
	static boolean dfs(int cur, int parent) {
		if(visited[cur])
			return true;
		
		int size = graph.get(cur).size();
		visited[cur] = true;
		HashSet<Integer> set = new HashSet<>();
        	//인접한 정점 HashSet 저장
		for(int next : graph.get(cur)) {
			if(next!= parent)
				set.add(next);
		}
        	//입력한 순서로 HashSet 비교 및 DFS 탐색 진행
		while(!set.isEmpty()) {
			int temp = result.poll();
			if(set.contains(temp)) {
				set.remove(temp);
				if(!dfs(temp,cur))
						return false;
				}else
					return false;
		}
		return true;
	}
}

 

댓글