주요 키워드 : 인정합 위치로 이동, 상하좌우, 가로, 세로, 대각선 이동
문) 차세대 영농인 한나는 강원도 고랭지에서 유기농 배추를 재배하기로 하였다. 농약을 쓰지 않고 배추를 재배하려면 배추를 해충으로부터 보호하는 것이 중요하기 때문에, 한나는 해충 방지에 효과적인 배추흰지렁이를 구입하기로 결심한다. 이 지렁이는 배추 근처에 서식하며 해충을 잡아 먹음으로써 배추를 보호한다. 특히, 어떤 배추에 배추흰지렁이가 한 마리라도 살고 있으면 이 지렁이는 인접한 다른 배추로 이동할 수 있어, 그 배추들 역시 해충으로부터 보호받을 수 있다. 한 배추의 상하좌우 네 방향에 다른 배추가 위치한 경우에 서로 인접해있는 것이다.
한나가 배추를 재배하는 땅은 고르지 못해서 배추를 군데군데 심어 놓았다. 배추들이 모여있는 곳에는 배추흰지렁이가 한 마리만 있으면 되므로 서로 인접해있는 배추들이 몇 군데에 퍼져있는지 조사하면 총 몇 마리의 지렁이가 필요한지 알 수 있다.
제한사항

| M | 10 |
|---|---|
| N | 8 |
| K | 17 |
K개의 배추 위치
| 0 | 0 |
|---|---|
| 1 | 0 |
| 1 | 1 |
| 4 | 2 |
| 4 | 3 |
| 4 | 5 |
| 2 | 4 |
| 3 | 4 |
나의 풀이
package programmers;
public class Dfs5 {
final static int MAX = 50 + 10;
static boolean[][] map;
static int[][] DIRS = {{-1,0},{1,0},{0,-1},{0,1}};
public static void dfs(int y, int x) {
map[y][x] = false;
for(int[] dir : DIRS) {
int newY = y + dir[0];
int newX = x + dir[1];
if(map[newY][newX]){
dfs(newY, newX);
}
}
}
public static int solution(int M, int N, int K, int[][] connections) {
map = new boolean[MAX][MAX];
for(int i = 0; i < K; i++) {
int x = connections[i][0];
int y = connections[i][1];
map[y+1] [x+1] = true;
}
int answer = 0;
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(map[i][j]) {
answer++;
dfs(i, j);
}
}
}
System.out.println(answer);
return answer;
}
public static void main(String[] args) {
int[][] connections = {{0, 0}, {1, 0}, {1, 1}, {4, 2}, {4, 3}, {4, 5}
,{2,4},{3,4},{7,4},{8,4},{9,4},{7,5},{8,5},{9,5},{7,6},{8,6},{9,6}};
solution(10,8,17, connections);
}
}
정리
인접한 다른 배추로 이동, 상하좌우 -> DFS/BFSvisited 배열을 생략할 수는 없을까?문) 인제대학교 생화학연구실에 재직중인 석교수는 전류가 침투(percolate) 할 수 있는 섬유 물질을 개발하고 있다. 이 섬유 물질은 2차원 M × N 격자로 표현될 수 있다. 편의상 2차원 격자의 위쪽을 바깥쪽(outer side), 아래쪽을 안쪽(inner side)라고 생각하기로 한다. 또한 각 격자는 검은색 아니면 흰색인데, 검은색은 전류를 차단하는 물질임을 뜻하고 흰색은 전류가 통할 수 있는 물질임을 뜻한다. 전류는 섬유 물질의 가장 바깥쪽 흰색 격자들에 공급되고, 이후에는 상하좌우로 인접한 흰색 격자들로 전달될 수 있다.
김 교수가 개발한 섬유 물질을 나타내는 정보가 2차원 격자 형태로 주어질 때, 바깥쪽에서 흘려 준 전류가 안쪽까지 침투될 수 있는지 아닌지를 판단하는 프로그램을 작성하시오.
Figure 1(a)

Figure 1(b)

예를 들어, Figure 1(a) 에서는 바깥쪽에서 공급된 전류가 안쪽까지 침투하지만, Figure 1(b)에서는 그렇지 못한다.
입력
첫째 줄에는 격자의 크기를 나타내는 M (2 ≤ M ≤ 1,000) 과 N (2 ≤ N ≤ 1,000) 이 주어진다. M줄에 걸쳐서, N개의 0 또는 1 이 공백 없이 주어진다. 0은 전류가 잘 통하는 흰색, 1은 전류가 통하지 않는 검은색 격자임을 뜻한다.
| N | 5 |
|---|---|
| M | 6 |

visited 배열 사용

나의 풀이
package programmers;
public class Dfs6 {
final static int MAX = 1000 + 10;
static boolean[][] map;
static boolean[][] visited;
static int[][] DIRS = {{-1,0},{1,0},{0,-1},{0,1}};
static boolean answer;
public static boolean dfs(int y, int x, int N) {
if(y == N) {
return true;
}
visited[y][x] = true;
for(int[] dir : DIRS) {
int newY = y + dir[0];
int newX = x + dir[1];
if(map[newY][newX] && !visited[newY][newX]){
if (dfs(newY, newX, N)) {
return true;
}
}
}
return false;
}
public static void solution(int N, int M, int[][] connections) {
map = new boolean[MAX][MAX];
visited = new boolean[MAX][MAX];
// 1. map 정보 반영
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
map[i][j] = connections[i-1][j-1] == 0;
}
}
// 2. dfs 수행
for(int j = 1; j <= M; j++) {
if(map[1][j]&& dfs(1,j,N)) {
System.out.println("YES");
return;
}
}
System.out.println("NO");
}
public static void main(String[] args) {
int[][] connections = {
{0, 1, 0, 1, 0, 1},
{0, 1, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 1},
{1, 0, 0, 0, 1, 1},
{0, 0, 1, 0, 1, 1}};
solution(5,6, connections);
}
}
visited 2차원 배열을 쓰지 않는 방법
package programmers;
public class Dfs6 {
final static int MAX = 1000 + 10;
static boolean[][] map;
static int[][] DIRS = {{-1,0},{1,0},{0,-1},{0,1}};
static boolean answer;
public static boolean dfs(int y, int x, int N) {
if(y == N) {
return true;
}
map[y][x] = false;
for(int[] dir : DIRS) {
int newY = y + dir[0];
int newX = x + dir[1];
if(map[newY][newX]){
if (dfs(newY, newX, N)) {
return true;
}
}
}
return false;
}
public static void solution(int N, int M, int[][] connections) {
map = new boolean[MAX][MAX];
// 1. map 정보 반영
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
map[i][j] = connections[i-1][j-1] == 0;
}
}
// 2. dfs 수행
for(int j = 1; j <= M; j++) {
if(map[1][j]&& dfs(1,j,N)) {
System.out.println("YES");
return;
}
}
System.out.println("NO");
}
public static void main(String[] args) {
int[][] connections = {
{0, 1, 0, 1, 0, 1},
{0, 1, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 1},
{1, 0, 0, 0, 1, 1},
{0, 0, 1, 0, 1, 1}};
solution(5,6, connections);
}
}
문) 정사각형으로 이루어져 있는 섬과 바다 지도가 주어진다. 섬의 개수를 세는 프로그램을 작성하시오.
한 정사각형과 가로, 세로 또는 대각선으로 연결되어 있는 사각형은 걸어갈 수 있는 사각형이다.
두 정사각형이 같은 섬에 있으려면, 한 정사각형에서 다른 정사각형으로 걸어서 갈 수 있는 경로가 있어야 한다. 지도는 바다로 둘러싸여 있으며, 지도 밖으로 나갈 수 없다.

keyword
섬의 개수
가로, 세로 또는 대각선으로 연결
한 정사각형에서 다른 정사각형으로 걸어거 갈 수 있는 경로
| w | 5 |
|---|---|
| h | 4 |


map, visited 2차원 배열 모두 사용
package programmers;
public class Dfs7 {
final static int MAX = 50 + 10;
static boolean[][] map;
static boolean[][] visited;
static int[] dirY = {-1,-1,0,1,1,1,0,-1};
static int[] dirX = {0,1,1,1,0,-1,-1,-1};
public static void dfs(int y, int x) {
visited[y][x] = true;
for(int i = 0; i < 8; i++) {
int newY = y + dirY[i];
int newX = x + dirX[i];
if(map[newY][newX] && !visited[newY][newX]) {
dfs(newY, newX);
}
}
}
public static int solution(int N, int M, int[][] connections) {
int answer = 0;
map = new boolean[MAX][MAX];
visited = new boolean[MAX][MAX];
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
map[i][j] = connections[i-1][j-1] == 1;
}
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(map[i][j] && !visited[i][j]) {
dfs(i,j);
answer++;
}
}
}
System.out.println(answer);
return answer;
}
public static void main(String[] args) {
int[][] connections = {
{1, 0, 1, 0, 0},
{1, 0, 0, 0, 0},
{1, 0, 1, 0, 1},
{1, 0, 0, 1, 0}};
solution(4,5, connections);
}
}
map 2차원 배열만 사용
package programmers;
public class Dfs7 {
final static int MAX = 50 + 10;
static boolean[][] map;
static int[] dirY = {-1,-1,0,1,1,1,0,-1};
static int[] dirX = {0,1,1,1,0,-1,-1,-1};
public static void dfs(int y, int x) {
map[y][x] = false;
for(int i = 0; i < 8; i++) {
int newY = y + dirY[i];
int newX = x + dirX[i];
if(map[newY][newX]) {
dfs(newY, newX);
}
}
}
public static int solution(int N, int M, int[][] connections) {
int answer = 0;
map = new boolean[MAX][MAX];
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
map[i][j] = connections[i-1][j-1] == 1;
}
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(map[i][j]) {
dfs(i,j);
answer++;
}
}
}
System.out.println(answer);
return answer;
}
public static void main(String[] args) {
int[][] connections = {
{1, 1, 1, 0, 1},
{1, 0, 1, 0, 1},
{1, 0, 1, 0, 1},
{1, 0, 1, 1, 1}};
solution(4,5, connections);
}
}
문) 형택이는 건축가이다. 지금 막 형택이는 형택이의 남자 친구 기훈이의 집을 막 완성시켰다. 형택이는 기훈이 방의 바닥 장식을 디자인했고, 이제 몇 개의 나무 판자가 필요한지 궁금해졌다. 나무 판자는 크기1의 너비를 가졌고, 양수의 길이를 가지고 있다. 기훈이 방은 직사각형 모양이고, 방 안에는 평행한 모양의 정사각형으로 나누어져 있다.
이제 - 와 |로 이우어진 바닥 장식 모양이 주어진다. 만약 두 개의 -가 인접해 있고, 같은 행에 있다면, 두 개는 같은 나무 판자이고, 두 개의 |가 인접해 있고, 같은 열에 있다면, 두 개는 같은 나무 판자이다.
기훈이의 방 바닥을 장식하는데 필요한 나무 판자의 개수를 출력하는 프로그램을 작성하시오.
keyword
두 개의 - 가 인접해 있고, 같은 행에 있다면
두 개의 | 가 인접해 있고, 같은 열에 있다면
| N | 4 |
|---|---|
| M | 4 |

map, visited 2차원 배열 사용
package programmers;
public class Dfs8 {
final static int MAX = 50 + 10;
static char[][] map;
static boolean[][] visited;
public static void dfs(int y, int x) {
visited[y][x] = true;
if(map[y][x] == '-' && map[y][x+1] == '-') dfs(y,x+1);
if(map[y][x] == '|' && map[y+1][x] == '|') dfs(y+1,x);
}
public static int solution(int N, int M, char[][] connections) {
int answer = 0;
map = new char[MAX][MAX];
visited = new boolean[MAX][MAX];
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
map[i][j] = connections[i-1][j-1] ;
}
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(!visited[i][j]) {
dfs(i,j);
answer++;
}
}
}
System.out.println(answer);
return answer;
}
public static void main(String[] args) {
char[][] connections = {
{'-', '-', '-', '-'},
{'-', '-', '-', '-'},
{'-', '-', '-', '-'},
{'-', '-', '-', '-'}};
solution(4,4, connections);
}
}
map 2차원 배열만 사용
package programmers;
public class Dfs8 {
final static int MAX = 50 + 10;
static char[][] map;
public static void dfs(int y, int x) {
char cur = map[y][x];
map[y][x] = 0;
if(cur == '-' && map[y][x+1] == '-') dfs(y,x+1);
if(cur == '|' && map[y+1][x] == '|') dfs(y+1,x);
}
public static int solution(int N, int M, char[][] connections) {
int answer = 0;
map = new char[MAX][MAX];
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
map[i][j] = connections[i-1][j-1] ;
}
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(map[i][j] != 0) {
dfs(i,j);
answer++;
}
}
}
System.out.println(answer);
return answer;
}
public static void main(String[] args) {
char[][] connections = {
{'-', '-', '-', '-'},
{'-', '-', '-', '-'},
{'-', '-', '-', '-'},
{'-', '-', '-', '-'}};
solution(4,4, connections);
}
}
문) ‘쩰리’는 점프하는 것을 좋아하는 젤리다. 단순히 점프하는 것에 지루함을 느낀 ‘쩰리’는 새로운 점프 게임을 해보고 싶어 한다. 새로운 점프 게임의 조건은 다음과 같다.
새로운 게임이 맘에 든 ‘쩰리’는, 계속 게임을 진행해 마침내 최종 단계에 도달했다. 하지만, 게임을 진행하는 구역이 너무 넓어져버린 나머지, 이 게임에서 이길 수 있는지 없는지 가늠할 수 없어졌다. ‘쩰리’는 유능한 프로그래머인 당신에게 주어진 구역에서 승리할 수 있는 지 알아봐 달라고 부탁했다. ‘쩰리’를 도와 주어진 게임 구역에서 끝 점(오른쪽 맨 아래 칸)까지 도달할 수 있는지를 알아보자!
N,M : 세로, 가로 (2 <= N,M <= 3)
출력
keyword
정사각형의 구역 내부
정사각형의 가장 왼쪽, 가장 위의 칸
오른쪽과 아래
가장 오른쪽, 가장 아래칸
현재 밟고 있는 칸에 쓰여 있는 수 만큼
map, visited 2차원 배열을 사용한 방법
package programmers;
public class Dfs9 {
final static int MAX = 3 + 100 + 10;
static int[][] map;
static boolean[][] visited;
static int[] dirY = {1,0};
static int[] dirX = {0,1};
public static void dfs(int y, int x, int N) {
visited[y][x] = true;
if(y == N && x == N) return;
for(int i = 0; i < 2; i++) {
int newY = y + dirY[i] * map[y][x];
int newX = x + dirX[i] * map[y][x];
if(!visited[newY][newX]) {
dfs(newY, newX, N);
}
}
}
public static int solution(int N, int[][] connections) {
int answer = 0;
map = new int[MAX][MAX];
visited = new boolean[MAX][MAX];
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= N; j++) {
map[i][j] = connections[i-1][j-1] ;
}
}
dfs(1,1,N);
if(visited[N][N]) {
System.out.println("HaruHaru");
}else {
System.out.println("Hing");
}
return answer;
}
public static void main(String[] args) {
int[][] connections = {
{1, 1, 10},
{1, 5, 1},
{2, 2, -1}};
solution(3, connections);
}
}
map 2차원 배열만 사용한 방법
package programmers;
public class Dfs9 {
final static int MAX = 3 + 100 + 10;
static int[][] map;
static int[] dirY = {1,0};
static int[] dirX = {0,1};
public static void dfs(int y, int x, int N) {
int value = map[y][x];
map[y][x] = 0;
if(y == N && x == N) return;
for(int i = 0; i < 2; i++) {
int newY = y + dirY[i] * value;
int newX = x + dirX[i] * value;
if(value != 0) {
dfs(newY, newX, N);
}
}
}
public static int solution(int N, int[][] connections) {
int answer = 0;
map = new int[MAX][MAX];
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= N; j++) {
map[i][j] = connections[i-1][j-1] ;
}
}
dfs(1,1,N);
if(map[N][N] == 0) {
System.out.println("HaruHaru");
}else {
System.out.println("Hing");
}
return answer;
}
public static void main(String[] args) {
int[][] connections = {
{1, 1, 10},
{1, 5, 1},
{2, 2, -1}};
solution(3, connections);
}
}