[문제]

N×M크기의 배열로 표현되는 미로가 있다.

1 0 1 1 1 1
1 0 1 0 1 0
1 0 1 0 1 1
1 1 1 0 1 1

미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.

위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

 

[입력]

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

 

[출력]

첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.

 

[예제]


>문제 풀이

 최단 경로를 찾는 문제라고 해서 BFS로 풀었습니다.

이제 BFS의 동작 원리를 알았을 뿐 이런문제를 처음 풀어봐서, '목적지 까지 가는 경로가 여러개일 경우 어디로 가느냐에 따라 cnt값도 달라질텐데, 재귀를 쓰지않고 cnt를 어떻게 따로 저장해둘지'에서 막혔었습니다.

 

(그래서 로직이 같고, 문제점을 해결한 다른 분들의 코드를 참조하여 공부하였습니다.)

방문한 mat[][]들을 이전 mat[][]값으로 부터 누적 카운팅 해서 최종적으로는 mat[N-1][M-1]을 출력하도록 했습니다.

 

+)그리고 이차 배열의 인덱스 값을 큐에 저장해야하기 때문에 x값 y값을 순서대로 offer, poll하도록 구현했습니다.

 

변수는 nx(now x값)= x(이전 위치x값)+ dx(x값의 변화량); 이런 의미로 넣었습니다.

	public static void bfs(int x, int y) {
		int[] dx= {-1, 0, 0, 1};
		int[] dy= {0, -1, 1, 0};
		int nx, ny;
		
		Queue<Integer> que= new LinkedList<Integer>();
		que.offer(x);
		que.offer(y);
		visited[x][y]=1;
		cnt++;
		
		while(!que.isEmpty()) {
			x=que.poll();
			y=que.poll();
			for(int j=0; j<4; j++) {
				nx= x+dx[j];
				ny= y+dy[j];
				if(nx>=0&&nx<N&&ny>=0&&ny<M) {
					if(mat[nx][ny]>0&&visited[nx][ny]!=1) {
						visited[nx][ny]=1;
						mat[nx][ny]= mat[x][y]+1;
						que.offer(nx);
						que.offer(ny);
					}
				}//if
			}
		}//while
		
	}//bfs

 

>전체 코드

 

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
	static int N, M, cnt=0;
	static int visited[][], mat[][];
	
	public static void main(String [] args) {
		
		Scanner scan= new Scanner(System.in);
		
		N= scan.nextInt();
		M= scan.nextInt();
		visited= new int[N][M];
		mat= new int[N][M];
		
		String str;
		for(int i=0; i<N; i++) {
			str= scan.next();
			for(int j=0; j<M; j++) {
				mat[i][j]= Integer.parseInt(str.charAt(j)+"");	
			}
		}
		
		bfs(0,0);
		
		System.out.println(mat[N-1][M-1]);
		
	}
	
	public static void bfs(int x, int y) {
		int[] dx= {-1, 0, 0, 1};
		int[] dy= {0, -1, 1, 0};
		int nx, ny;
		
		Queue<Integer> que= new LinkedList<Integer>();
		que.offer(x);
		que.offer(y);
		visited[x][y]=1;
		cnt++;
		
		while(!que.isEmpty()) {
			x=que.poll();
			y=que.poll();
			for(int j=0; j<4; j++) {
				nx= x+dx[j];
				ny= y+dy[j];
				if(nx>=0&&nx<N&&ny>=0&&ny<M) {
					if(mat[nx][ny]>0&&visited[nx][ny]!=1) {
						visited[nx][ny]=1;
						mat[nx][ny]= mat[x][y]+1;
						que.offer(nx);
						que.offer(ny);
					}
				}//if
			}
		}//while
		
	}//bfs
	
}

www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

 

1) DFS(Depth-First Search): 깊이 우선 탐색

: 스택 혹은 재귀함수를 이용한다.

:갈 수 있는 만큼 깊게 들어가고, 더이상 갈 수 없을 때 backtracking 한다.

 

1. 시작 노드를 스택에 넣고 방문 처리를 한다.

2. 스택의 최상단 노드에 연결된 노드 중 (보통) 번호가 낮은 노드를 스택에 넣고 방문처리

3. 최상단 노드의 인접노드가 없을 때 까지 반복하고, 인접노드가 없으면 스택에서 최상단 노드를 꺼낸다.

4. 위의 과정을 반복한다.

 

이런식으로 반복하게 된다.

 

<DFS 구현코드>

	public static void dfs(int start) {
		visit[start]=1;
		for(int i=1; i<=N; i++) {
			if(mat[start][i]==1 && visit[i]!=1) {
				dfs(i);
			}
		}
	}//dfs

인접행렬로 구현한 경우, 시간 복잡도는 O(n^2)

 

 

 

1) BFS(Breadth-First Search): 너비 우선 탐색

: 큐(Queue)를 사용.

: 현재 정점에서 갈 수 있는 노드들을 모두 큐에 넣는다.

 

1. 시작노드를 큐에 넣고, 방문처리

2. 큐에서 노드를 꺼내서, 해당 노드의 인접 노드 중 방문하지 않은 노드를 모두 큐에 삽입하고 방문처리

3. 더이상 2번 과정을 수행할 수 없을 때까지 반복한다.

 

<BFS 구현코드>

	public static void bfs(int start) {
		int temp;
		Queue<Integer> queue= new LinkedList<Integer>();
		queue.offer(start);
		visit[start]=1;
		System.out.print(start+" ");
		
		while(!queue.isEmpty()) {
			temp= queue.poll();
			for(int i=1; i<=N; i++) {
				if(mat[temp][i]==1&&visit[i]!=1) {
					queue.offer(i);
					visit[i]= 1;
					System.out.print(i+" ");
				}
			}
		}
		
	}//bfs

 

 

 

유튜브 '동빈나' 님의 영상과 다른 글들을 보고 정리한 것입니다.

www.youtube.com/watch?v=7C9RgOcvkvo

 

[문제]

그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.

 

[입력]

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.

 

[출력]

첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.

 

[예제]


>문제 풀이

 DFS와 BFS에 대한 이해가 있었다면 풀 수 있는 가장 기본적인 문제인 것 같다.

그러나, 나는 이해가 없었기에,, 개념부터 공부하고 이 문제를 풀었다.

 

>전체 코드

 

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
	static int N, M, V;
	static int visit[], mat[][];
	
	public static void main(String [] args) {
		int p1, p2;
		
		Scanner scan= new Scanner(System.in);
		
		N= scan.nextInt();
		M= scan.nextInt();
		V= scan.nextInt();
		
		visit= new int[N+1];
		mat= new int[N+1][N+1];
		for(int i=0; i<M; i++) {
			p1= scan.nextInt();
			p2= scan.nextInt();
			mat[p1][p2]=mat[p2][p1]=1;
		}
		
		dfs(V);
		System.out.println();
		Arrays.fill(visit, 0); //초기화
		bfs(V);
		
	}
	
	public static void dfs(int start) {
		visit[start]=1;
		System.out.print(start+" ");
		for(int i=1; i<=N; i++) {
			if(mat[start][i]==1 && visit[i]!=1) {
				dfs(i);
			}
		}
	}//dfs
	
	public static void bfs(int start) {
		int temp;
		Queue<Integer> queue= new LinkedList<Integer>();
		queue.offer(start);
		visit[start]=1;
		System.out.print(start+" ");
		
		while(!queue.isEmpty()) {
			temp= queue.poll();
			for(int i=1; i<=N; i++) {
				if(mat[temp][i]==1&&visit[i]!=1) {
					queue.offer(i);
					visit[i]= 1;
					System.out.print(i+" ");
				}
			}
		}
		
	}//bfs
}

www.acmicpc.net/problem/1260

 

1260번: DFS와 BFS

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사

www.acmicpc.net

 

+ Recent posts