알고리즘/백준

[백준] 등산 (1486번)

cho____sh 2020. 8. 13. 15:33
728x90

문제

세준이는 등산광이다. 세준이는 높은 곳에서 도시를 내려다 보는 것을 좋아한다. 하지만, 겁이 많은 세준이는 어두워지기 전에 호텔로 내려오려고 한다.

세준이가 가려고하는 산의 지도가 입력으로 주어진다. 산의 지도를 M이라고 했을 때, M[i][j]는 (i,j)의 높이가 M[i][j]라는 것을 의미한다. 그 값이 'A'-'Z'일 때는 0-25를 뜻하는 것이고, 'a'-'z'일 때는, 26-51을 뜻한다.

세준이의 호텔은 (0,0)에 있다. 그리고, 세준이는 지금 위치에서 바로 인접한 정수 좌표 중 높이의 차이가 T보다 크지 않은 곳으로만 다닐 수 있다.

만약 세준이가 현재 위치에서 높이가 낮은 곳이나 같은 곳으로 이동한다면 시간은 1초가 걸린다. 하지만 높은 곳으로 이동한다면 두 위치의 높이의 차이의 제곱만큼 시간이 걸린다. 예를 들어 높이가 5에서 높이가 9인 곳으로 간다면, 시간은 (5-9)2=16초가 걸린다. 하지만, 높이가 9인 곳에서 5인 곳으로 간다면 시간은 1초가 걸린다.

산의 지도와, T, 그리고 어두워지는 시간 D가 주어졌을 때, 세준이가 D보다 크지 않은 시간 동안 올라갈 수 있는 최대 높이를 구하는 프로그램을 작성하시오.(세준이는 호텔에서 출발해서 호텔로 돌아와야 한다.)

입력

첫째 줄에 산의 세로크기 N과 가로크기 M 그리고, T와 D가 주어진다. N과 M은 25보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 지도가 주어진다. T는 52보다 작거나 같은 자연수이고, D는 1,000,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 세준이가 갈 수 있는 가장 높은 곳의 높이를 출력한다.

예제 입력 1 복사

6 6 6 36 AABCDE GJIHGF MKLMNO STSRQP YUVWXY edcbaZ

예제 출력 1 복사

30


갈 수 있는 산의 최대 높이를 구하는 문제이다. 

단 등산한 후 하산까지 마쳐야 한다. 이걸 제대로 안 읽어서 틀렸었다.

산의 높이차 T와, 최대 시간 D를 고려하면서 산을 방문해주면 된다.

 

다익스트라나 플로이드 와샬 알고리즘을 통해 해결할 수도 있지만, bfs를 통해 해결했다.

우선 시작점 (1,1)에서 각 지점으로 등산하는 함수 bfs()를 돌린 후,

(1,1)로 하산하는 함수 bfs2()를 돌렸다.

 

bfs()는 문제에서 요구하는 그대로 구현했지만, bfs2()가 약간 헷갈릴 수 있다.

원래는 모든 지점에서 (1,1)로 가는 거리를 구하려면 bfs를 좌표 수만큼 여러번 돌려야 할 것 같아서,

(1,1)로 도착하는 거리를 구한다고 가정하고, 시간 계산을 거꾸로 했다.

예를들어 (1,2)에서 (1,1)로 하산한다고 할 때, 높이가 6과 3이라면 시간은 1이 걸릴 것이다. 이 시간을 (1,2)지점에 기록하는 것이다.

그렇다보니 다음 지점이 오르막일 때엔 시간 + 1을 하고, 내리막일 때 높이차만큼 제곱을 해서 더하는 방식으로 해야한다. 

 

혹시나 이해가 잘 안될까봐 아래 예시 결과를 올렸다.

visit가 등산 시간 배열이고 back이 하산 시간 배열이다. 참고하길 바란다.

 

이렇게 등산과 하산 시간을 모두 구한 후에 최종적인 계산만 하면 된다.

두 시간의 합이 D를 넘지 않을 때 해당 위치의 최대 높이를 반복문을 통해서 구하면 된다.

등산이나 하산이 불가능한 지역은 예외처리를 해야한다. 까먹지 말자.

 

코드 원본 : https://github.com/chosh95/STUDY/blob/master/BaekJoon/2020/%EB%93%B1%EC%82%B0%20(1486%EB%B2%88).cpp

 

chosh95/STUDY

프로그래밍 문제 및 알고리즘 정리. Contribute to chosh95/STUDY development by creating an account on GitHub.

github.com

 

C++ 코드

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int N, M, T, D;
int res;
int p[26][26]; // 지도 정보
int visit[26][26]; // 등산 시간
int back[26][26]; // 하산 시간
int dx[4] = { -1,0,0,1 };
int dy[4] = { 0,-1,1,0 };

void bfs()
{
	memset(visit, -1, sizeof(visit));
	queue<pair<int, int>> q;
	q.push({ 1,1 });
	visit[1][1] = 0;

	while (!q.empty()) {
		int x = q.front().first;
		int y = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nx = x + dx[i];
			int ny = y + dy[i];
			if (nx<1 || ny<1 || nx>N || ny>M) continue;
			if (abs(p[nx][ny] - p[x][y]) > T) continue; //높이차가 T보다 크면 불가능
			if (p[nx][ny] <= p[x][y]) {
				if (visit[x][y] + 1 > D) continue; // D시간 초과시 방문 불가능
				if (visit[nx][ny] == -1 || visit[nx][ny] > visit[x][y] + 1) {
					visit[nx][ny] = visit[x][y] + 1;
					q.push({ nx,ny });
				}
			}
			else {
				int nextTime = (p[nx][ny] - p[x][y]) * (p[nx][ny] - p[x][y]);
				if (visit[x][y] + nextTime > D) continue; //D시간 초과시 방문 불가능
				if (visit[nx][ny] == -1 || visit[nx][ny] > visit[x][y] + nextTime) {
					visit[nx][ny] = visit[x][y] + nextTime;
					q.push({ nx,ny });
				}
			}
		}
	}
}

void bfs2()
{
	memset(back, -1, sizeof(back));
	queue<pair<int, int>> q;
	q.push({ 1,1 });
	back[1][1] = 0;

	while (!q.empty()) {
		int x = q.front().first;
		int y = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nx = x + dx[i];
			int ny = y + dy[i];
			if (nx<1 || ny<1 || nx>N || ny>M) continue;
			if (abs(p[nx][ny] - p[x][y]) > T) continue; //높이차가 T보다 크면 불가능
			if (p[x][y] > p[nx][ny]) {
				int nextTime = (p[x][y] - p[nx][ny]) * (p[x][y] - p[nx][ny]);
				if (back[x][y] + nextTime > D) continue; // D시간 초과시 방문 불가능
				if (back[nx][ny] == -1 || back[nx][ny] > back[x][y] + nextTime) {
					back[nx][ny] = back[x][y] + nextTime;
					q.push({ nx,ny });
				}
			}
			else {
				if (back[x][y] + 1 > D) continue; // D시간 초과시 방문 불가능
				if (back[nx][ny] == -1 || back[nx][ny] > back[x][y] + 1) {
					back[nx][ny] = back[x][y] + 1;
					q.push({ nx,ny });
				}
			}
		}
	}
}

int main()
{
	cin >> N >> M >> T >> D;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			char a;
			cin >> a;
			if ('A' <= a && a <= 'Z') p[i][j] = (a - 'A');
			else p[i][j] = (a - 'a' + 26);
		}
	}

	bfs(); //호텔 -> 등산
	bfs2(); //산->호텔

	res = p[1][1];
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			if (visit[i][j] == -1 || back[i][j] == -1) continue;
			if (visit[i][j] + back[i][j] <= D) {
				res = max(res, p[i][j]);
			}
		}
	}

	cout << res;
}
728x90