알고스팟
1 초 (추가 시간 없음) | 128 MB | 35652 | 15383 | 10502 | 42.139% |
문제
알고스팟 운영진이 모두 미로에 갇혔다. 미로는 N*M 크기이며, 총 1*1크기의 방으로 이루어져 있다. 미로는 빈 방 또는 벽으로 이루어져 있고, 빈 방은 자유롭게 다닐 수 있지만, 벽은 부수지 않으면 이동할 수 없다.
알고스팟 운영진은 여러명이지만, 항상 모두 같은 방에 있어야 한다. 즉, 여러 명이 다른 방에 있을 수는 없다. 어떤 방에서 이동할 수 있는 방은 상하좌우로 인접한 빈 방이다. 즉, 현재 운영진이 (x, y)에 있을 때, 이동할 수 있는 방은 (x+1, y), (x, y+1), (x-1, y), (x, y-1) 이다. 단, 미로의 밖으로 이동 할 수는 없다.
벽은 평소에는 이동할 수 없지만, 알고스팟의 무기 AOJ를 이용해 벽을 부수어 버릴 수 있다. 벽을 부수면, 빈 방과 동일한 방으로 변한다.
만약 이 문제가 알고스팟에 있다면, 운영진들은 궁극의 무기 sudo를 이용해 벽을 한 번에 다 없애버릴 수 있지만, 안타깝게도 이 문제는 Baekjoon Online Judge에 수록되어 있기 때문에, sudo를 사용할 수 없다.
현재 (1, 1)에 있는 알고스팟 운영진이 (N, M)으로 이동하려면 벽을 최소 몇 개 부수어야 하는지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1은 벽을 의미한다.
(1, 1)과 (N, M)은 항상 뚫려있다.
출력
첫째 줄에 알고스팟 운영진이 (N, M)으로 이동하기 위해 벽을 최소 몇 개 부수어야 하는지 출력한다.
예제 입력 1 복사
3 3
011
111
110
예제 출력 1 복사
3
예제 입력 2 복사
4 2
0001
1000
예제 출력 2 복사
0
예제 입력 3 복사
6 6
001111
010000
001111
110001
011010
100010
예제 출력 3 복사
2
힌트
이 문제는 알고스팟에서도 풀 수 있다.
알고리즘 분류
풀이
미로 크기 N*M 총 1*1의 방 <- 좌표 방
빈방은 자유롭게 이동 가능, 벽은 부숴야함.
방의 이동은 상하좌우로만 이동 가능
1,1에 있는 운영진이 N,M으로 이동하려면 벽을 최소 몇개 부수어야 하는지 구해야함.
입력
가로 크기 M
세로 크기 n 주어진
다음 n개의 줄에 미로의 상태를 나타내는 숫자 0과 1 주어짐
0은 빈방, 1은 벽
1,1과 N,M은 항상 뚫려 있음
첫 째 줄에 알고스팟 운영진이 N,M까지 갈 때 벽을 최소 몇 개 부수어야 하는지 출력 필요
모든 정점의 가중치는 1아니면 0으로 처리
일단 가중치가 0아니면 1만 있어서 dfs나 bfs로 계산할 생각을 해본다.
하나의 좌표에서 움직일 수 있는 것은 상하좌우 4방향
다음 방향에서 이동도 상하좌우 4방향
DFS의 시간 복잡도는 O(E + V)
N*N 배열에서
O(N + N*N -2N) = N개의 Edge, N*N의 vertex, 온 방향 제외하면 2N 제거
= O(N*2) = dfs 1번에 100* 100, 루트 갯수가 10만개이면 10만 * 100 하면 100억, bad일경우 터짐
bfs도 비슷한 상황일것으로 보임.
그러면 길찾기 알고리즘에서 dfs 다거르고 다익스트라 알고리즘 사용하면 될 것으로 예상
입력을 받아 저장하는 2차원 array와 경로를 계산하는 2차원 array가 필요할 것으로 보임.
0 0 0
1 1 1
으로 값이 들어왔을 때
경로 표시는
0 inf inf
inf inf inf
로 초기화되어 있음.
0,1 가는 방법
1. 0,0 -> 0, 1 문 0개 부숨
2. 0,0 -> 1, 0 -> 1,1-> 0, 1 문 2개 부숨
3. 0,0 -> 1,0 -> 1,1 -> 1, 2 -> 0,2 -> 0,1 문 3개 부숨
문을 부순 것인지 안부순 것인지에 대해 판별이 필요함
1. 문을 부쉈다면 현재까지 부순 문의 갯수 + 1
2. 안부쉈다면 현재까지 부순 문의 갯수를 저장
1번 방법 표기
x, y = 0, 0, 오른쪽 이동
dist[x][y] = 0 dist[nx][ny] = min(dist[nx][ny], dist[x][y])
2번 방법 표기
x,y = 0, 0 , 아래 오른쪽 위로 이동
dist[x][y] = 0
dist[x+1][y] = 1
dist[x+1][y+1] = 2
dist[x+1][y] = 2
dist[x+1][y] = min(dist[x+1][y], dist[x][y])
이 방법을 이용해서 하나씩 비교할 것
코드
package test1261;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class Main {
static int N;
static int M;
static int result;
static int arr[][];
static int dist[][];
static int[] dx = {1, 0, 0, -1};
static int[] dy = {0, 1, -1, 0};
static class Point implements Comparable<Point> {
int x;
int y;
int cost;
Point(int x, int y, int cost) {
this.x = x;
this.y = y;
this.cost = cost;
}
@Override
public int compareTo(Point o) {
// TODO Auto-generated method stub
// 정렬 이유 다익스트라를 이용하여 벽 갯수가 적은대로 정렬하는 것이 효과적
return this.cost - o.cost;
}
}
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
MyScanner sc = new MyScanner(System.in);
M = sc.nextInt();
N = sc.nextInt();
arr = new int[N+1][M+1];
dist = new int[N+1][M+1];
for(int i = 1; i <N+1; i++) {
String tempArr = sc.nextToken(); //띄어쓰기 없음
for(int j = 1; j <M+1; j++) {
arr[i][j] = tempArr.charAt(j-1) - '0';
dist[i][j] = 987654321;
}
}
algorithm();
sc.write(dist[N][M]+"\n");
sc.close();
}
static void algorithm() {
PriorityQueue<Point> pq = new PriorityQueue<>();
pq.offer(new Point(1, 1, 0)); // 첫줄은 항상 cost가 0
dist[1][1] = 0;
//pq가 비워질때까지 반복
while(!pq.isEmpty()) {
Point point = pq.poll();
int x= point.x;
int y= point.y;
// 상하좌우 처리
for(int i = 0; i < 4; i++) {
int nx = x + dx[i]; //이동된 x
int ny = y + dy[i]; //이동된 y
// 범위가 벗어나면 cut 한다.
if(nx > N || ny > M || nx <= 0 || ny <= 0) {
continue;
}
// 기존 dist에 있는 문 부순 값이 이전에 있던 값 + 입력된 arr 문 값이면
if(dist[nx][ny] > dist[x][y] + arr[nx][ny]) {
dist[nx][ny] = dist[x][y] + arr[nx][ny]; // 변경
pq.offer(new Point(nx, ny, dist[nx][ny])); // 현재 위치와 cost 값을 추가
}
}
}
}
static class MyScanner {
final BufferedReader reader;
final BufferedWriter writer;
static StringTokenizer tokenizer = null;
MyScanner(InputStream in) {
reader = new BufferedReader(new InputStreamReader(in));
writer = new BufferedWriter(new OutputStreamWriter(System.out));
}
String nextToken() throws IOException {
if(tokenizer == null || !tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
int nextInt() throws NumberFormatException, IOException {
return Integer.parseInt(nextToken());
}
long nextLong() throws NumberFormatException, IOException {
return Long.parseLong(nextToken());
}
void write(String text) throws Exception{
writer.write(text);
}
void close() throws IOException {
reader.close();
writer.close();
}
}
}
'Algorithms > 2023 Pro 시험 준비' 카테고리의 다른 글
5419 북서풍 - 백준 (0) | 2023.07.31 |
---|---|
1655 가운데를 말해요 - 백준 (0) | 2023.07.24 |
2811 알약 - 백준 (0) | 2023.07.24 |
Pro 시험에서의 길찾기 알고리즘 (0) | 2023.07.19 |
10217 KCM Travel - 백준 (0) | 2023.07.17 |