acmicpc
[BAEKJOON] 2573. 빙산
코드와이
2021. 8. 6. 22:32
문제링크
https://www.acmicpc.net/problem/2573
2573번: 빙산
첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을
www.acmicpc.net
무한 시간초과...
백준의 질문검색을 통해 연산 시간을 줄일 수 있도록 수정했다.
- visited 확인 이차 배열을 정적 변수로 두지 않고, 입력 변수로 넣어준다.
- 덩어리를 분리하는 조건에 2번째 들어온다면 무조건 덩어리는 2개 이상이 되기 때문에 함수를 실행하지말고 break!
- 테두리 부분은 항상 0이기 때문에 이중 for 문으로 검사할 때 제외하고 검사한다.
package acmicpc.Gold4;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
// visited boolean 2차 배열을 static 으로 두고 연산을 하니까 시간초과...
// devide 함수에 인자값으로 넘겨주고, melt 에서도 따로 visited 를 선언하고 연산하니까 통과!!
// 덩어리를 확인하는 부분으로 2번째 들어오면 바로 break 걸어주기!!
public class 빙산 {
static int r, c, map[][];
static int[] dr = {-1,1,0,0};
static int[] dc = {0,0,-1,1};
static class Point{
int y, x;
public Point(int y, int x) {
super();
this.y = y;
this.x = x;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
r = Integer.parseInt(st.nextToken());
c = Integer.parseInt(st.nextToken());
map = new int[r][c];
for(int i = 0 ; i < r ; i++) {
st = new StringTokenizer(br.readLine());
for(int j = 0 ; j < c ; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
int ans = 0;
out: while(true) {
ans++;
// 빙산 녹이기
melt();
// dfs 로 나눠진 덩어리 찾기
int cnt = 0;
boolean[][] visited = new boolean[r][c];
for(int i = 1 ; i < r - 1 ; i++) {
for(int j = 1 ; j < c - 1 ; j++) {
if(map[i][j] != 0 && !visited[i][j]) {
// 두 덩어리 이상이면 break
// cnt 가 2가 되면 바로 끝내버리기
if(cnt == 1) break out;
divide(i,j,visited);
cnt++;
}
}
}
if(cnt == 0) {
ans = 0;
break;
}
}
System.out.println(ans);
}
public static void divide(int y, int x, boolean[][] visited) {
visited[y][x] = true;
for(int d = 0 ; d < 4 ; d++) {
int nr = y + dr[d];
int nc = x + dc[d];
if(nr < 1 || nc < 1 || nr >= r - 1 || nc >= c - 1) continue;
if(map[nr][nc] != 0 & !visited[nr][nc]) divide(nr,nc, visited);
}
}
public static void melt() {
// 큐에 빙산 넣기, 빙산은 true
boolean[][] visited = new boolean[r][c];
Queue<Point> queue = new LinkedList<>();
for(int i = 1 ; i < r ; i++) {
for(int j = 1 ; j < c ; j++) {
if(map[i][j] != 0) {
queue.add(new Point(i,j));
visited[i][j] = true;
}
}
}
while(!queue.isEmpty()) {
Point q = queue.poll();
for(int d = 0 ; d < 4 ; d++) {
int nr = q.y + dr[d];
int nc = q.x + dc[d];
if(nr < 0 || nc < 0 || nr >= r || nc >= c) continue;
// 빙산의 높이가 0 이 되면 break
if(map[q.y][q.x] == 0 ) break;
// 닿는 부분이 0 이고 visited 가 true 인 부분
if(map[nr][nc] == 0 && !visited[nr][nc]) map[q.y][q.x]--;
}
}
}
}