알고리즘/백준
5427_불 ******** => 시간초과
베리영young
2024. 6. 20. 01:45
메모리 초과 ->> visit 배열로 해결
시간 초과 ->>헐?
두 가지 타파법
1. 게임 시작 전에 bfs 돌면서, 각 빈 칸에 몇 초 후에 불이 붙는지 미리 저장해두고, 사람만 움직인다
2. queue에 발화점을 저장해 둔다. (한 번 발화를 한 곳은 그 다음부터 옆으로 더 번질 위험이 없으므로 빼고, 새로운 발화점을 추가한다)
시간초 과가 난 코드
package afterMiracom_0618;
import java.awt.Point;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import java.util.Scanner;
public class Main_bj_5427_불 {
static int w, h, time; //너비, 높이
static char[][] startMap;
static int[] dx = {-1,1,0,0};
static int[] dy = {0,0,-1,1};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for (int test = 0; test < t; test++) {
time = -1;
w = sc.nextInt();
h = sc.nextInt();
Point sanggeun = null; //상근이 위치
startMap = new char[h][w];
for (int i = 0; i < h; i++) {
String s = sc.next();
for (int j = 0; j < w; j++) {
// #': 벽, '@': 상근, '*': 불
startMap[i][j] = s.charAt(j);
if (startMap[i][j] == '@') {
sanggeun = new Point(i, j);
startMap[i][j] = '.';
}
}
}
//입력 끝
bfs_5427(sanggeun);
if(time == -1) System.out.println("IMPOSSIBLE");
else System.out.println(time);
} //테스트 케이스 끝
}
private static void bfs_5427(Point sanggeun) {
Queue<Escape> q = new ArrayDeque<>();
boolean[][] visit = new boolean[h][w];
visit[sanggeun.x][sanggeun.y] = true;
q.add(new Escape(sanggeun, 0, visit, startMap));
while (!q.isEmpty()) {
Escape escape = q.poll();
char[][] map = copyMap(escape.map);
boolean[][] flashPoint = checkFlashPoint(escape.map);
//불이 번진다 , map 갱신
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if(flashPoint[i][j]) { //발화점이면, 4방 탐색으로 불 번지기
burning(i, j, map); // map이 갱신이 되나
}
}
}
//상근이가 움직인다 => 추가. 1초 후에 번질 곳이면 못 간다, 범위 벗어나면 끝이다
for (int d2 = 0; d2 < 4; d2++) {
int nx = escape.sanggeun.x + dx[d2];
int ny = escape.sanggeun.y + dy[d2];
//메모리 초과 방지
if(escape.move > w*h) return;
if(nx<0 || ny<0 || nx>=h || ny>= w) { //탈출!
time = escape.move + 1;
return;
}
else {
if(map[nx][ny] == '.') { //갈 수 있는 곳이면, 1초 후에 불이 번지는지 확인
if( isNormalOneSecondLater(nx, ny, map) && !escape.visit[nx][ny]) {
escape.visit[nx][ny] = true;
q.add(new Escape(new Point(nx, ny), escape.move+1, escape.visit, map));
}
}
}
}
}
}
private static boolean[][] checkFlashPoint(char[][] map) { //****
boolean[][] flashPoint = new boolean[h][w]; //발화점을 표시하는 map... 불 번질 때 , 옮겨붙은 곳에서 다시 불이 움직이면 안 되니까
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if(map[i][j] == '*') flashPoint[i][j] = true;
}
}
return flashPoint;
}
private static boolean isNormalOneSecondLater(int x, int y, char[][] map) {
// for (int d = 0; d < 4; d++) {
// int nx = x + dx[d];
// int ny = y + dy[d];
//
// if(nx>=0 && ny>=0 && nx<h && ny<w && map[nx][ny] == '*') return false;
// }
return true;
}
private static void burning(int x, int y, char[][] map) {
for (int d = 0; d < 4; d++) {
int nx = x + dx[d];
int ny = y + dy[d];
if(nx>=0 && ny>=0 && nx<h && ny<w && map[nx][ny] == '.') { //빈 칸이거나, 사람 있는 곳이면 불 번지기
map[nx][ny] = '*';
}
}
}
private static char[][] copyMap(char[][] map) {
char[][] newMap = new char[h][w];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
newMap[i][j] = map[i][j];
}
}
return newMap;
}
}
class Escape {
Point sanggeun;
int move;
boolean[][] visit;
char[][] map;
public Escape(Point sanggeun, int move, boolean[][] visit, char[][] map) {
super();
this.sanggeun = sanggeun;
this.move = move;
this.visit = visit;
this.map = map;
}
}