-
백준 14890번 경사로 :: 마이구미알고리즘 풀이/수학 2018. 4. 6. 18:41반응형
이 글은 백준 알고리즘 문제 14890번 "경사로" 를 풀이한다.
접근 방법은 단순 문제 이해를 통한 구현이 된다.
2017 삼성 SW 역량 테스트 기출문제이다.
오늘은 이 지도에서 지나갈 수 있는 길이 몇 개 있는지 알아보려고 한다. 길이란 한 행 또는 한 열 전부를 나타내며, 한쪽 끝에서 다른쪽 끝까지 지나가는 것이다.
길을 지나갈 수 있으려면 길에 속한 모든 칸의 높이가 모두 같아야 한다. 또는, 경사로를 놓아서 지나갈 수 있는 길을 만들 수 있다. 경사로는 높이가 항상 1이며, 길이는 L이다. 또, 개수는 매우 많아 부족할 일이 없다. 경사로는 낮은 칸과 높은 칸을 연결하며, 아래와 같은 조건을 만족해야한다.
- 경사로는 낮은 칸에 놓으며, L개의 연속된 칸에 경사로의 바닥이 모두 접해야 한다.
- 낮은 칸과 높은 칸의 높이 차이는 1이어야 한다.
- 경사로를 놓을 낮은 칸의 높이는 모두 같아야 하고, L개의 칸이 연속되어 있어야 한다.
아래와 같은 경우에는 경사로를 놓을 수 없다.
- 경사로를 놓은 곳에 또 경사로를 놓는 경우
- 낮은 칸과 높은 칸의 높이 차이가 1이 아닌 경우
- 낮은 지점의 칸의 높이가 모두 같지 않거나, L개가 연속되지 않은 경우
- 경사로를 놓다가 범위를 벗어나는 경우
본인은 문제를 한번에 이해하기 힘들었다.
하지만 완전히 이해하기 어려운 문제가 아니다.
또한 어려운 알고리즘을 요구하는 것이 아니기에 문제를 꼼꼼히 읽고 풀어보길 추천한다.
문제의 핵심은 경사로가 필요한 곳의 높이 차이는 1이라는 것과 L 길이만큼 연속되어있다는 것이다.
다음 그림으로 표현할 수 있다.
위와 같이 높이 차가 1이고, L 만큼 연속되어있어야 경사로를 배치할 수 있다.
그렇지 않은 경우는 다음과 같다.
왼쪽은 높이 차가 1이 아니기 때문에, 경사로를 배치할 수 없다.
오른쪽은 L만큼 배치할 수 있는 공간이 없기 때문에 경사로를 배치할 수 없게 된다.
이렇게만 보면, 단순히 연속된 수에 대해 카운터를 쌓은 후, 높은 칸을 발견하면 경사로를 놓을 수 있는지 판단하면 된다.
그림으로 표현하면 다음과 같다.
하지만 여기서 문제는 연속된 수를 쌓다가 높은 칸이 아닌 낮은 칸을 만날 수도 있다는 것이다.
그렇게 되면, 지금까지 지나오면서 쌓은 카운터를 이용할 수 없게 된다.
즉, 높은 칸을 기준으로 다음 칸들로부터 경사로를 배치할 수 있는 지 판단해야한다.
크게 높은 칸을 만났을 때와 낮은 칸을 만났을 때를 구분한다.
큰 흐름은 다음과 같다.
- 길을 지나오면서 연속된 수에 대해서는 카운터를 증가시킨다.
- 연속되지 않는 수를 만난다면, 높은 칸인지 낮은 칸인지 확인한다.
- 높은 칸이라면, 쌓아온 카운터를 통해 경사로를 배치할 수 있는 지 확인한다.
- 낮은 칸이라면, L만큼 지나가면서 경사로를 배치할 수 있는 지 연속 유무를 확인한다.
Github - https://github.com/hotehrud/acmicpc/blob/master/SAMSUMG/14890.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899static int[][] road;static int[] height;static int n, l;private void solve() {n = sc.nextInt();l = sc.nextInt();road = new int[n * 2][n];int ans = n * 2;for (int i = 0; i < n; i++) {String[] input = sc.readLine().split(" ");for (int j = 0; j < n; j++) {road[i][j] = Integer.parseInt(input[j]);}}for (int i = n; i < n * 2; i++) {for (int j = 0; j < n; j++) {road[i][j] = road[j][i - n];}}// 높은 칸을 만났을 경우 => 지나온 길을 통해 경사로 배치 판단 가능.// 낮은 칸을 만났을 경우 => 낮은 칸부터 길을 지나가면서 경사로를 배치할 수 있는 지 판단해야함.for (int i = 0; i < n * 2; i++) {int target = road[i][0];height = new int[11];height[target] = 1;int j = 1;while (j < n) {int next = road[i][j];if (!vaildHeight(target, next)) {// 높이 차가 1보다 크면 경사로 배치 불가능--ans;break;}if (target != next) {if (target < next) {// 높은 칸 만났을 경우if (!high(target, next)) {--ans;break;}} else {// 낮은 칸 만났을 경우if (!low(i, j, target, next)) {--ans;break;}j += l - 1;}// 기준이 되는 칸 갱신target = next;} else {// 같은 높이의 칸을 뜻하기 때문에, L의 길이를 갖는 경사로 배치 판단을 위한 카운터 증가height[target]++;}j++;}}System.out.println(ans);}public static boolean low(int i, int j, int target, int next) {// 길이가 L인 경사로를 놓을 수 있는지만 판단하면 되기에 l 만큼 돌린다.for (int k = 0; k < l; k++) {if (j + k == n) {break;}if (road[i][j + k] == next) {height[next]++;}}if (height[next] < l) {return false;}height[next] -= l;return true;}public static boolean high(int target, int next) {if (height[target] < l) {return false;}// 다음을 위해 카운터 배열 갱신height[target] = 0;height[next] = 1;return true;}public static boolean vaildHeight(int a, int b) {int gap = Math.abs(a - b);if (gap > 1) {return false;}return true;}cs 반응형'알고리즘 풀이 > 수학' 카테고리의 다른 글
백준 1652번 누울 자리를 찾아라 :: 마이구미 (0) 2018.08.14 백준 6064번 카잉 달력 :: 마이구미 (2) 2018.07.16 백준 10837번 동전 게임 :: 마이구미 (0) 2018.04.01 백준 1244번 스위치 켜고 끄기 :: 마이구미 (0) 2018.03.06 백준 1236번 성 지키기 :: 마이구미 (0) 2018.03.06