탐색(DFS&BFS)

κ³½μ„œν˜„Β·2022λ…„ 8μ›” 10일
0

πŸ“Œ κ·Έλž˜ν”„λ₯Ό νƒμƒ‰ν•˜λŠ” λ°©λ²•μ—λŠ” 크게 깊이 μš°μ„  탐색(DFS)와 λ„ˆλΉ„ μš°μ„  탐색(BFS)κ°€ μžˆλ‹€.

  • κ·Έλž˜ν”„λ₯Ό νƒμƒ‰ν•œλ‹€ β†’ ν•˜λ‚˜μ˜ μ •μ μœΌλ‘œλΆ€ν„° μ‹œμž‘ν•˜μ—¬ 주어진 λͺ¨λ“  정점듀을 μ°¨λ‘€λŒ€λ‘œ ν•œ λ²ˆμ”© λ°©λ¬Έν•œλ‹€λŠ” 뜻!

DFS(깊이 μš°μ„  탐색)

μž¬κ·€ ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•˜κ±°λ‚˜ μŠ€νƒμ„ μ΄μš©ν•¨ !! β†’ μ‹œκ°„λ³΅μž‘λ„λŠ” O(V+E) // V: λ…Έλ“œ 수, E: 에지 수

  • κ·Έλž˜ν”„ μ™„μ „ 탐색 기법 쀑 ν•˜λ‚˜λ‘œ, κ·Έλž˜ν”„μ˜ μ‹œμž‘ λ…Έλ“œμ—μ„œ μΆœλ°œν•˜μ—¬ 탐색할 ν•œ μͺ½ λΆ„κΈ°λ₯Ό μ •ν•˜μ—¬ μ΅œλŒ€ κΉŠμ΄κΉŒμ§€ 탐색을 마친 ν›„ λ‹€λ₯Έ μͺ½ λΆ„κΈ°λ‘œ μ΄λ™ν•˜μ—¬ λ‹€μ‹œ 탐색을 μˆ˜ν–‰ν•¨
  • μž¬κ·€λ‘œ κ΅¬ν˜„ν•  경우 μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°μ— μœ μ˜ν•΄μ•Ό ν•œλ‹€.
  • DFS ν™œμš© μ˜ˆλ‘œλŠ” λ‹¨μ ˆμ  μ°ΎκΈ°, λ‹¨μ ˆμ„  μ°ΎκΈ°, 사이클 μ°ΎκΈ°, μœ„μƒμ •λ ¬ 등이 μžˆλ‹€.

핡심 이둠

πŸ“Œν•œ 번 λ°©λ¬Έν•œ λ…Έλ“œ 재방문 λΆˆκ°€ β†’ λ°©λ¬Έ 체크 λ°°μ—΄ ν•„μš”
πŸ“Œμ΅œλŒ€ν•œ 깊이 λ‚΄λ €κ°„ λ’€, 더이상 갈 곳이 μ—†λŠ” 경우 μ˜†μœΌλ‘œ 이동함

μŠ€νƒμ„ ν†΅ν•œ κ΅¬ν˜„ 원리



πŸ’‘ κ²°λ‘ 

  1. λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©λ¬Έν•˜κ³ μž ν•˜λŠ” κ²½μš°μ— 이 방법을 선택
  2. DFSκ°€ BFS보닀 μ’€ 더 간단함
  3. λͺ¨λ“  λ…Έλ“œλ₯Ό νƒμƒ‰ν•˜κΈ° λ•Œλ¬Έμ— BFS에 λΉ„ν•΄ 속도가 느림 β†’ μ‹œκ°„ μ΄ˆκ³Όλ‚˜λ©΄ BFS둜 ν’€κΈ°!

πŸ‘©πŸ»β€πŸ’» κ΄€λ ¨λ¬Έν•­ (λ°±μ€€ 2023번 μ‹ κΈ°ν•œ μ†Œμˆ˜ μ°ΎκΈ°)

λ§€μ»€λ‹ˆμ¦˜

  1. 1자리의 μ†Œμˆ˜λŠ” 2, 3, 5, 7둜 κ³ μ •μ΄λ―€λ‘œ 이λ₯Ό λ³„λ„μ˜ String 배열에 λ„£κ³  for문을 λŒλ¦°λ‹€. λ˜ν•œ, λ’·μžλ¦¬μ— 올 수 μžˆλŠ” μˆ˜λŠ” μ§μˆ˜μ™€ 5λ₯Ό μ œμ™Έν•œ λ‚˜λ¨Έμ§€(1, 3, 7, 9)만 κ°€λŠ₯ν•˜λ―€λ‘œ 이 λ˜ν•œ λ³„λ„μ˜ String 배열에 λ„£λŠ”λ‹€.
  2. μž¬κ·€λ₯Ό μ΄μš©ν•΄ 숫자λ₯Ό λ§Œλ“€κ³ _dfsλ‚˜ λ°±νŠΈλž˜ν‚ΉμœΌλ‘œ κ΅¬ν˜„ κ°€λŠ₯
  3. μ†Œμˆ˜μΈμ§€ νŒλ³„ν•  λ•ŒλŠ” Math.sqrt()λ₯Ό ν™œμš© !! β†’ μ—λΌν† μŠ€ν…Œλ„€μŠ€μ˜ 체
  4. 1~3 과정을 λ°˜λ³΅ν•œ ν›„ N자리수의 μ†Œμˆ˜μž„μ΄ ν™•μΈλ˜λ©΄ sb.append(prime)ν•˜κΈ°!

μ½”λ“œ

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

public class BJ2023 {
	static String [] nextNum = {"1", "3", "7", "9"}; 
  // 2의배수, 5의 λ°°μˆ˜λŠ” μ†Œμˆ˜κ°€ 될 수 μ—†μŒ
	static StringBuilder sb= new StringBuilder();
	static int N;
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		String [] alwaysPrime = {"2", "3", "5","7"};
		
		N = Integer.parseInt(br.readLine());
		
		for(int i = 0; i<4; i++) {
			makePrime(alwaysPrime[i], 1);
		}
		System.out.println(sb.toString());
		
	}
	static void makePrime(String s, int cnt) {
		
		if(cnt == N) {
			sb.append(s+"\n");
			return;
		}
		
		for(int i = 0; i<4; i++) {
			if(isPrime(s+nextNum[i]))
				makePrime(s+nextNum[i], cnt+1);
		}
	}
	static boolean isPrime(String s) {
		
		int tmp = Integer.parseInt(s);
		
		for(int i = 2; i<Math.sqrt(tmp); i++) {
			if(tmp % i == 0) return false;
		}
		return true;
	}
}

BFS(λ„ˆλΉ„ μš°μ„  탐색)

큐λ₯Ό μ΄μš©ν•΄μ„œ κ΅¬ν˜„ν•¨! β†’ μ‹œκ°„λ³΅μž‘λ„λŠ” O(V+E) // V: λ…Έλ“œ 수, E: 에지 수

  • κ·Έλž˜ν”„ μ™„μ „ 탐색 방법 쀑 ν•˜λ‚˜λ‘œ, μ‹œμž‘ λ…Έλ“œμ—μ„œ μΆœλ°œν•΄ μ‹œμž‘ λ…Έλ“œλ₯Ό κΈ°μ€€μœΌλ‘œ κ°€κΉŒμš΄ λ…Έλ“œλ₯Ό λ¨Όμ € λ°©λ¬Έν•˜λ©΄μ„œ νƒμƒ‰ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜
  • FIFO 방식이기 λ•Œλ¬Έμ— 큐둜 κ΅¬ν˜„ν•¨

핡심 이둠

πŸ“Œν•œ 번 λ°©λ¬Έν•œ λ…Έλ“œ 재방문 λΆˆκ°€ β†’ λ°©λ¬Έ 체크 λ°°μ—΄ ν•„μš”
πŸ“Œνλ₯Ό μ΄μš©ν•œ FIFO 방식 !

큐λ₯Ό ν†΅ν•œ κ΅¬ν˜„ 원리



πŸ’‘ κ²°λ‘ 

  1. λͺ©ν‘œ λ…Έλ“œμ— λ„μ°©ν•˜λŠ” κ²½λ‘œκ°€ μ—¬λŸ¬ 개일 λ•Œ μ΅œλ‹¨ 경둜λ₯Ό 보μž₯함
  2. O(n)의 탐색 μˆ˜ν–‰ μ‹œκ°„μ΄ μ†Œμš”λ˜κ³  DFS 보닀 μˆ˜ν–‰ μ‹œκ°„μ΄ μ’‹λ‹€.

πŸ‘©πŸ»β€πŸ’» κ΄€λ ¨λ¬Έν•­ (λ°±μ€€ 2468 μ•ˆμ „μ˜μ—­)

package homework;

import java.io.*;
import java.util.*;
/*
5
6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7
 */
public class Main_bj_2468 {
	static int N;
	static int[][] map;
	static boolean[][] checked;
	static int[] dx = {1, 0, -1, 0};
	static int[] dy = {0,- 1, 0, 1};
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		StringBuilder sb= new StringBuilder();
		
		N= Integer.parseInt(br.readLine());
		map = new int[N][N];
		
		int maxH=0;
		for(int i=0; i<N; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j=0; j<N; j++) {
				map[i][j] = Integer.parseInt(st.nextToken());
				if(map[i][j] > maxH) {
					maxH =map[i][j];
				}
			}
		}
		
		int max =0;
		
		for(int h=0; h<maxH; h++) {
			checked = new boolean[N][N];
			int cnt=0;
			for(int i=0; i<N; i++) {
				for(int j=0; j<N; j++) {
					if(!checked[i][j] && map[i][j] > h){
						//cnt+=dfs(i,j,h); 
						cnt+=bfs(i,j,h); 
					}
				}
			}
			max = Math.max(max, cnt);
		}

		System.out.println(max);
	}
	// DFS탐색
	static int dfs(int x, int y, int h) {
		checked[x][y] = true;
		for(int i=0; i<4; i++) {
			int nx = x +dx[i];
			int ny = y +dy[i];
			if(nx >=0 && nx<N && ny>=0 && ny<N && map[nx][ny] > h && !checked[nx][ny]) {
				dfs(nx, ny, h);
			}
		}
		return 1;
	}
	// BFS탐색
	static int bfs(int x, int y, int h) {
		Queue<int[]> q = new ArrayDeque<int[]>();
		checked[x][y] = true;
		q.offer(new int[] {x, y});
		while(!q.isEmpty()) {
			int [] pos =q.poll();
			x = pos[0];
			y = pos[1];
			for(int d =0; d<4; d++) {
				int nx = x+dx[d];
				int ny = y+dy[d];			
				if(nx >=0 && nx<N && ny>=0 && ny<N && map[nx][ny] > h && !checked[nx][ny]) {
					checked[nx][ny] = true; // 쀑볡될 수 μžˆμœΌλ‹ˆκΉŒ μ—¬κΈ°μ„œ check!
					q.offer(new int[] {nx, ny});
				}
			}	
		}
		return 1;
	}
}

πŸ’­ DFS? BFS?

  • κ·Έλž˜ν”„μ˜ λͺ¨λ“  정점을 λ°©λ¬Έν•˜λŠ” 것이 μ£Όμš”ν•œ 문제
    • λ‹¨μˆœνžˆ λͺ¨λ“  정점을 λ°©λ¬Έν•˜λŠ” 것이 μ€‘μš”ν•œ 문제의 경우 DFS, BFS 두 가지 방법 쀑 μ–΄λŠ 것을 μ‚¬μš©ν•΄λ„ 상관없닀.
  • 경둜의 νŠΉμ§•μ„ μ €μž₯해둬야 ν•˜λŠ” 문제 β†’ μ΄λ™ν•œ μ •μ μ˜ 값을 가지고 계속 연산을 ν•˜λŠ” 경우(μž¬κ·€μ μœΌλ‘œ ν˜ΈμΆœλ˜λŠ”κ²½μš°)
    • 예λ₯Ό λ“€λ©΄ 각 정점에 μˆ«μžκ°€ μ ν˜€μžˆκ³  aλΆ€ν„° bκΉŒμ§€ κ°€λŠ” 경둜λ₯Ό κ΅¬ν•˜λŠ”λ° κ²½λ‘œμ— 같은 μˆ«μžκ°€ 있으면 μ•ˆ λœλ‹€λŠ” 문제 λ“±, 각각의 κ²½λ‘œλ§ˆλ‹€ νŠΉμ§•μ„ μ €μž₯해둬야 ν•  λ•ŒλŠ” DFSλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. (BFSλŠ” 경둜의 νŠΉμ§•μ„ 가지지 λͺ»ν•©λ‹ˆλ‹€)
  • μ΅œλ‹¨κ±°λ¦¬ ꡬ해야 ν•˜λŠ” 문제
    • 미둜 μ°ΎκΈ° λ“± μ΅œλ‹¨κ±°λ¦¬λ₯Ό ꡬ해야 ν•  경우, BFSκ°€ μœ λ¦¬ν•¨.
    • 깊이 μš°μ„  νƒμƒ‰μœΌλ‘œ 경둜λ₯Ό 검색할 경우 처음으둜 λ°œκ²¬λ˜λŠ” 해닡이 μ΅œλ‹¨κ±°λ¦¬κ°€ 아닐 수 μžˆμ§€λ§Œ,λ„ˆλΉ„ μš°μ„  νƒμƒ‰μœΌλ‘œ ν˜„μž¬ λ…Έλ“œμ—μ„œ κ°€κΉŒμš΄ κ³³λΆ€ν„° μ°ΎκΈ° λ•Œλ¬Έμ— 경둜 탐색 μ‹œ λ¨Όμ € μ°Ύμ•„μ§€λŠ” 해닡이 곧 μ΅œλ‹¨κ±°λ¦¬ !

0개의 λŒ“κΈ€