스터디사이트 : https://www.acmicpc.net/
JAVA 알고리즘 : 섬의 개수[백준 4963]
※ 문제 Url
https://www.acmicpc.net/problem/4963
그래프 알고리즘 분야 중 입문과정인듯하다..
여러 구글링을 통해 원리를 알아냈는데 깨우치기까지 시간이 참 오래도걸렸다 ㅡㅡㅋ
※ 해결법
내가 머릿속으로 정리된 이 문제에서의 해결법은,
1. 테스트케이스마다 섬(1)과 바다(0)의 정보가 입력된 그대로 int[][] 2차원배열을 만든다.
2. 섬과 바다 정보가 들어있는 2차원 int[][] 배열을 탐색해서 섬(1)을 발견하면, 섬의 갯수를 1씩 증가 시킨다.
2-1. 섬을 발견한 위치의 value를 1 -> 0으로 바꾼다.
2-2. 섬을 발견한 위치 근처에 붙어있는 섬이 있는 지 탐색한다.
2-3. 그 위치 근처에 섬이 있다면, 2-1과 2-2를 반복한다. 더이상 근처에 섬이 없을때까지.
그런데,
2-1 단계를 왜 하냐면, 아래 그림을 보라.
노란색으로 색칠한 곳이 현재 내가 검사하는 대상이다. 섬을 발견한 위치.
그 다음 단계인 <NEXT>를 보면,
이 단계가 위의 2-1단계라고 보면 되는데, 빨간색 화살표와 파란색 화살표가 있다.
옆에도 섬(1)이고, 아래도 섬(1)이기 때문에, 반복문을 돌다가 가장 먼저 발견한 곳으로 가는 것이다.
<NEXT - RED>나 <NEXT - BLUE>단계를 보면,
만약에 저 그림과 달리 검사대상을 1 -> 0 으로 바꾸지 않고 그대로 1로 냅뒀을 때
우리가 검사했던 대상으로 다시 되돌아가지 말라는 법이 없지 않는가?
그렇게되면 무한루프에 빠질 수 있기 때문에 검사대상을 1 -> 0으로 바꾸는 것이다.
그리고 나는 1번단계에서 int[][] 배열 정의하는 방식을 특이하게 행과 열에다가 2씩 크기를 더 늘려서 만들었다.
이유는 검사대상 주위의 인덱스들을 탐색할때 모서리나 귀퉁이에 있으면 IndexOutOfBoundsException이 뜰까봐..
하지만 그러한 것을 걸러내는 기능을 하는 메소드도 얼마든지 만들 수 있다. 구글링하면 다른 사람들이 코딩한 것 대부분이 그렇다 ㅋ
그러나 나는 이 코드로도 맞았습니다! 를 얻어냈으므로..ㅋ 나중에 차차 연구를 ㅋ
※ 내가 푼 코드
태클 얼마든지 환영합니다.
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.util.StringTokenizer; | |
public class Main { | |
// 섬과바다 표시배열 | |
int[][] island; | |
// 섬과바다 검사여부배열 | |
boolean[][] isCheck; | |
public static void main(String[] args) throws IOException { | |
new Main(); | |
} //end main() | |
Main() throws IOException { | |
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | |
StringTokenizer token = null; | |
StringBuilder sb = new StringBuilder(); | |
int islands = 0; | |
while (true) { | |
// TestCase마다 섬 갯수 초기화 | |
islands = 0; | |
String inputLine = br.readLine(); | |
if (inputLine.equals("00") || inputLine.equals("0 0")) break; | |
// line 1. | |
token = new StringTokenizer(inputLine, " "); | |
int width = Integer.parseInt(token.nextToken()); | |
int height = Integer.parseInt(token.nextToken()); | |
// 주어진 입력범위 밖은 모두 바다 (value = 0) 라는 정보를 넣기위해 | |
// 섬이 붙어있는 지 검사 시에 검사대상 주위를 둘러싼 인덱스를 구하기위해 IndexOutofBounds가 안 나게 하기위해 | |
island = new int[height+2][width+2]; | |
// line x(2~height) | |
// island[][] 배열값 채워넣기 | |
for (int n = 1; n < height+1; n++) { | |
token = new StringTokenizer(br.readLine(), " "); | |
int tokenIndex=1; | |
while(token.hasMoreTokens()){ | |
int element = Integer.parseInt(token.nextToken()); | |
island[n][tokenIndex] = element; | |
tokenIndex++; | |
} | |
} //end for | |
// * 배열을 탐색해 가며 1인 요소는 0을 만들고, 주위에 1인 요소를 발견하면 같은방식으로 1이 끊기는 위치까지 탐색한다. | |
for(int h=1; h<height+1; h++){ // 행 | |
for(int w=1; w<width+1; w++){ // 열 | |
if(island[h][w]==1){ | |
islands++; | |
getIslands(h, w); | |
} | |
} //end for | |
} //end for | |
sb.append(islands+"\n"); | |
} //end while | |
// 결과출력 | |
System.out.println(sb.toString()); | |
} // end Main_2() | |
public void getIslands(int h, int w){ | |
// 검사대상. 즉 1이 표시된 위치에 대해서 0으로 바꿈 | |
island[h][w] = 0; | |
// 대상을 둘러싸는 인덱스 | |
// ex) 대상 [1,1] : 주위 [0,0] [0,1] [0,2] / [1,0] [1,2] / [2,0] [2,1] [2,2] | |
int[] search_h = {-1, -1, -1, 0, 0, 1, 1, 1}; | |
int[] search_w = {-1, 0, 1, -1, 1, -1, 0, 1}; | |
for(int i=0; i<search_h.length; i++){ | |
int around_h = h + search_h[i]; | |
int around_w = w + search_w[i]; | |
// 주위에 1인 위치를 발견하면 재귀호출하여 그 위치에서도 근처에 1이 있는지 탐색. | |
if(island[around_h][around_w]==1){ | |
getIslands(around_h, around_w); | |
} | |
} //end for | |
} //end getIslands() | |
} |
'JAVA > JAVA 자료구조 알고리즘' 카테고리의 다른 글
JAVA 자료구조 : 최소 힙[백준 1927] (0) | 2017.06.04 |
---|---|
JAVA 알고리즘 : 줄 세우기[백준 2252] (0) | 2017.06.03 |
JAVA 알고리즘 : 이진 검색 트리[백준 5639] (0) | 2017.04.19 |
JAVA 알고리즘 : 셀프 넘버[백준 4673] (0) | 2017.04.19 |
JAVA 알고리즘 : 소수 판별하기 (0) | 2016.08.17 |