경사로 (14890)
1. 문제
2. 풀이
2-1. 조건
- 경사로는 높이 1, 길이 L이다.
- 경사로는 낮은 칸에 놓으며, L개의 연속된 칸에 경사로의 바닥이 모두 접해야 한다.
- 낮은 칸과 높은 칸의 높이 차이는 1이어야 한다.
- 경사로를 놓을 낮은 칸의 높이는 모두 같아야 하고, L개의 칸이 연속되어 있어야 한다.
2.2 풀이
위에서 정리한 조건에 부합하게 경사로를 설치해서
각 행과 열에 대해서 하나씩 지날 수 있는 길인지 체크해서 카운팅하는 문제입니다.
문제는 경사로 설치 구현이겠죠.
제가 구현한 방식은 이렇습니다.
// 경사로를 설치할 수 있는지 체크하고,
// 설치할 수 있다면 설치하고 true 리턴
// 설치할 수 없다면 false 리턴
static boolean isFit(int y, int x, int dir) {
// 이미 설치돼있을 때
if (fit[y][x]) return false;
// 원본 좌표 저장
int oriY = y;
int oriX = x;
// 이전 좌표의 높이
int prev = M[y][x];
// 경사로의 길이만큼 체크
for (int i = 0; i < L - 1; i++) {
y += my[dir];
x += mx[dir];
// 도로를 벗어났을 때
if (y < 0 || y >= N || x < 0 || x >= N) return false;
// 이전 좌표의 높이와 현재 좌표의 높이가 다를 때
if (prev != M[y][x]) return false;
// 이미 설치했을 때
if (fit[y][x]) return false;
// 이전 좌표의 높이 갱신
prev = M[y][x];
}
// 설치할 수 있다면 경사로를 설치
y = oriY;
x = oriX;
fit[y][x] = true;
for (int i = 0; i < L - 1; i++) {
y += my[dir];
x += mx[dir];
fit[y][x] = true;
}
return true;
}
설치할 좌표와 설치할 방향을 인자로 받아서 설치할 수 있는지 체크하고
설치가 가능하면 설치를 하는 함수입니다.
이 함수를 각 행과 열을 체크할 때 호출함으로서 지날 수 있는 도로인지 판별할 수 있습니다.
3. 전체 코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static int N, L, M[][], my[] = {-1, 0, 1, 0}, mx[] = {0, 1, 0, -1};
static boolean[][] fit;
// 경사로를 설치할 수 있는지 체크하고,
// 설치할 수 있다면 설치하고 true 리턴
// 설치할 수 없다면 false 리턴
static boolean isFit(int y, int x, int dir) {
// 이미 설치돼있을 때
if (fit[y][x]) return false;
// 원본 좌표 저장
int oriY = y;
int oriX = x;
// 이전 좌표의 높이
int prev = M[y][x];
// 경사로의 길이만큼 체크
for (int i = 0; i < L - 1; i++) {
y += my[dir];
x += mx[dir];
// 도로를 벗어났을 때
if (y < 0 || y >= N || x < 0 || x >= N) return false;
// 이전 좌표의 높이와 현재 좌표의 높이가 다를 때
if (prev != M[y][x]) return false;
// 이미 설치했을 때
if (fit[y][x]) return false;
// 이전 좌표의 높이 갱신
prev = M[y][x];
}
// 설치할 수 있다면 경사로를 설치
y = oriY;
x = oriX;
fit[y][x] = true;
for (int i = 0; i < L - 1; i++) {
y += my[dir];
x += mx[dir];
fit[y][x] = true;
}
return true;
}
public static void main(String[] args) throws Exception {
String[] s = br.readLine().split(" ");
N = Integer.parseInt(s[0]);
L = Integer.parseInt(s[1]);
M = new int[N][N];
fit= new boolean[N][N];
int r, c, cnt = 0;
for (r = 0; r < N; r++) {
s = br.readLine().split(" ");
for (c = 0; c < N; c++)
M[r][c] = Integer.parseInt(s[c]);
}
// 행 검사
out:
for (r = 0; r < N; r++) {
int prev = M[r][0];
for (c = 1; c < N; c++) {
int cur = M[r][c];
// 이전 좌표의 높이와 현재 좌표의 높이의 차이가 1보다 클 때
if (Math.abs(cur - prev) > 1) continue out;
// 현재 좌표가 이전 좌표보다 1크고 이전 좌표로부터 서쪽으로 경사로 설치가 불가능할 때
if (cur > prev && !isFit(r, c - 1, 3)) continue out;
// 현재 좌표가 이전 좌표보다 1작고 현재 좌표로부터 동쪽으로 경사로 설치가 불가능할 때
if (cur < prev && !isFit(r, c, 1)) continue out;
prev = cur;
}
cnt++;
}
// 설치했던 경사로 모두 제거
for (r = 0; r < N; r++)
for (c = 0; c < N; c++)
fit[r][c] = false;
// 열 검사
out:
for(c = 0; c < N; c++) {
int prev = M[0][c];
for (r = 1; r < N; r++) {
int cur = M[r][c];
// 이전 좌표의 높이와 현재 좌표의 높이의 차이가 1보다 클 때
if (Math.abs(cur - prev) > 1) continue out;
// 현재 좌표가 이전 좌표보다 1크고 이전 좌표로부터 북쪽으로 경사로 설치가 불가능할 때
if (cur > prev && !isFit(r - 1, c, 0)) continue out;
// 현재 좌표가 이전 좌표보다 1작고 현재 좌표로부터 남쪽으로 경사로 설치가 불가능할 때
if (cur < prev && !isFit(r, c, 2)) continue out;
prev = cur;
}
cnt++;
}
bw.write(cnt + "");
bw.close();
}
}
Author And Source
이 문제에 관하여(경사로 (14890)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@front/백준-경사로-14890저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)