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