알고리즘/백준
1261_알고스팟 **
베리영young
2024. 6. 23. 00:07
사용 알고리즘: 다익스트라
사용 언어: java
package week04;
import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Main_bj_1261_알고스팟 {
static int n, m, map[][], dp[][];
// static int ans; //최소 부숴야 할 벽 개수
static int[] dx = {1, 0}; //아래, 오른쪽으로만 가면 됨
static int[] dy = {0, 1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
m = Integer.parseInt(st.nextToken());
n = Integer.parseInt(st.nextToken());
map = new int[n][m];
// ans = n * m;
for (int i = 0; i < n; i++) {
String s = br.readLine();
for (int j = 0; j < m; j++) {
//0: 빈 칸, 1: 벽
map[i][j] = s.charAt(j) - '0';
}
}
//데이크스트라라고 한다..
dp = new int[n][m];
for(int i=0; i<n; i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
dp[0][0] = 0;
//입력 끝
dijkstra_1261();
System.out.println(dp[n-1][m-1]);
}
private static void dijkstra_1261() {
PriorityQueue<AlgoSpot> pq = new PriorityQueue<>((o1, o2) -> o1.move - o2.move);
boolean[][] visit = new boolean[n][m];
visit[0][0] = true;
pq.add(new AlgoSpot(new Point(0, 0), 0, 0));
while (!pq.isEmpty() ) {
AlgoSpot cur = pq.poll();
int x = cur.point.x;
int y = cur.point.y;
dp[x][y] = Math.min(dp[x][y], cur.crash);
if(cur.move >= n*m - 1) {
continue;
}
for (int d = 0; d < 2; d++) {
int nx = x + dx[d];
int ny = y + dy[d];
if(nx>=0 && ny>=0 && nx<n && ny<m && cur.move < n*m - 1) {
if(map[nx][ny] == 0) {
pq.add(new AlgoSpot(new Point(nx, ny), cur.move + 1, cur.crash));
}
else {
pq.add(new AlgoSpot(new Point(nx, ny), cur.move + 1, cur.crash + 1));
}
}
}
}
}
// private static int[][] copy_1261(int[][] map2) {
// int[][] map = new int[n][m];
//
// for (int i = 0; i < n; i++) {
// for (int j = 0; j < m; j++) {
// map[i][j] = map2[i][j];
// }
// }
// return map;
// }
}
class AlgoSpot {
Point point;
int move;
int crash;
// boolean[][] visit;
// int[][] map;
public AlgoSpot(Point point, int move, int crash) {
super();
this.point = point;
this.move = move;
this.crash = crash;
// this.visit = visit;
// this.map = map;
}
}
처음엔 bfs로 풀다가 , 이럴 거면 dp를 왜 만들었지! 했다.
여기서 dp는 [i][j] 위치로 갈 때까지 '부수는 벽의 최소 개수'를 의미한다.
그래서 우선순위 큐에서 poll할 때마다 dp[x][y] 값을 최소로 갱신한다.
..........
위의 코드는 메모리 초과가 난다.
주의 ** n과 m을 거꾸로 입력 받아야 한다....
통과된 코드
package week04;
import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Main_bj_1261_알고스팟 {
static int n, m, map[][], dp[][];
// static int ans; //최소 부숴야 할 벽 개수
static int[] dx = {1, 0, -1, 0}; //아래, 오른쪽으로만 가면 됨
static int[] dy = {0, 1, 0 ,-1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
m = Integer.parseInt(st.nextToken());
n = Integer.parseInt(st.nextToken());
map = new int[n][m];
// ans = n * m;
for (int i = 0; i < n; i++) {
String s = br.readLine();
for (int j = 0; j < m; j++) {
//0: 빈 칸, 1: 벽
map[i][j] = s.charAt(j) - '0';
}
}
//데이크스트라라고 한다..
dp = new int[n][m];
for(int i=0; i<n; i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
dp[0][0] = 0;
//입력 끝
dijkstra_1261();
System.out.println(dp[n-1][m-1]);
}
private static void dijkstra_1261() {
PriorityQueue<AlgoSpot> pq = new PriorityQueue<>((o1, o2) -> o1.move - o2.move);
boolean[][] visit = new boolean[n][m];
visit[0][0] = true;
pq.add(new AlgoSpot(new Point(0, 0), 0, 0));
while (!pq.isEmpty() ) {
AlgoSpot cur = pq.poll();
int x = cur.point.x;
int y = cur.point.y;
//메모리 초과
// dp[x][y] = Math.min(dp[x][y], cur.crash);
//
// if(cur.move >= n*m - 1) {
// continue;
// }
for (int d = 0; d < 4; d++) {
int nx = x + dx[d];
int ny = y + dy[d];
if(nx>=0 && ny>=0 && nx<n && ny<m && cur.move < n*m - 1) {
if(map[nx][ny] == 0) {
if (dp[nx][ny] > dp[x][y]) { //메모리 초과...
dp[nx][ny] = dp[x][y];
pq.add(new AlgoSpot(new Point(nx, ny), cur.move + 1, cur.crash));
}
// pq.add(new AlgoSpot(new Point(nx, ny), cur.move + 1, cur.crash));
}
else {
if (dp[nx][ny] > dp[x][y] + 1) {
dp[nx][ny] = dp[x][y] + 1;
pq.add(new AlgoSpot(new Point(nx, ny), cur.move + 1, cur.crash + 1));
}
// pq.add(new AlgoSpot(new Point(nx, ny), cur.move + 1, cur.crash + 1));
}
}
}
}
}
// private static int[][] copy_1261(int[][] map2) {
// int[][] map = new int[n][m];
//
// for (int i = 0; i < n; i++) {
// for (int j = 0; j < m; j++) {
// map[i][j] = map2[i][j];
// }
// }
// return map;
// }
}
class AlgoSpot {
Point point;
int move;
int crash;
// boolean[][] visit;
// int[][] map;
public AlgoSpot(Point point, int move, int crash) {
super();
this.point = point;
this.move = move;
this.crash = crash;
// this.visit = visit;
// this.map = map;
}
}
1. 시작점과 끝점이 항상 동일하니까, 오른쪽, 아래쪽으로만 움직이면 된다고 생각했는데, 예외가 있다.
0 0 1 0 0 0
1 0 0 0 1 0
이런 경우, 위로 올라가야 부수는 벽의 개수를 최소화 할 수 있다
2. 메모리 초과!
시간초과를 고려하여 이런 걸 넣었는데, 핵심은 이게 아니었다고 한다..^^..
// dp[x][y] = Math.min(dp[x][y], cur.crash);
//
// if(cur.move >= n*m - 1) {
// continue;
// }
메모리 초과는, 내가 설정해둔 pq의 크기가 너무 커지는 탓이었다.
그래서 add를 하는 순간에, dp값이 변경될 때만 add했어야 한다.