거의 알고리즘 일기장

백준 1520번 _ 내리막 길 본문

알고리즘 문제풀이

백준 1520번 _ 내리막 길

건우권 2020. 5. 4. 16:00

https://www.acmicpc.net/problem/1520

 

1520번: 내리막 길

여행을 떠난 세준이는 지도를 하나 구하였다. 이 지도는 아래 그림과 같이 직사각형 모양이며 여러 칸으로 나뉘어져 있다. 한 칸은 한 지점을 나타내는데 각 칸에는 그 지점의 높이가 쓰여 있으며, 각 지점 사이의 이동은 지도에서 상하좌우 이웃한 곳끼리만 가능하다. 현재 제일 왼쪽 위 칸이 나타내는 지점에 있는 세준이는 제일 오른쪽 아래 칸이 나타내는 지점으로 가려고 한다. 그런데 가능한 힘을 적게 들이고 싶어 항상 높이가 더 낮은 지점으로만 이동하여 목표 지

www.acmicpc.net

 접근

 주어진 조건들을 먼저보자.

 시간은 2초, MxN 행렬 (M, N <=500), 다음 위치는 현재위치보다 무조건 낮다.

 

 먼저 생각해 볼수 있는건 DFS다. 그런데 잘 생각해보면 이게 방향이 우측, 아래로만 간다는 조건도 없고 사방으로 갈수있기 때문에 대충 생각해봐도 시간오바다. ( 계산을 해서 보여주고 싶지만... 어떻게 계산해야될지도 모르겠다. 하지만, 2초라는 시간 안에는 수행할수 없다는것은 당연히 직관적으로 이해될 것임으로 넘어가겠다. )

 

 그렇다면 시간을 줄여야 할까?

 잘 생각해보면 도착점까지 간 경로에 포함된 곳에 다시 가는것은 시간낭비라는것을 알수있다. (이해가 안된다면 밑에 그림 참조)


 풀이방법

 정답부터 말하자면 DFS에 DP를 더해서 푸는 방법으로 풀 수있는 문제다.

 그렇다면 어떻게 DP를 적용할수 있을까?

 

 바로 도착점에 도달했던 경로에 겹치게 되면 바로 RETURN시켜 필요없는 연산을 하지 않는것이다. ( 가지치기 )

 DP[i][j] : i, j 지점에서 도착지점까지 갈수있는 경로의 개수 , 처음에 가보지 않은 지점은 -1로 초기화 할것. 

 

 (동작에 대한 GIF가 있으니 밑의 블로그에서 보면 이해가 빠를것이다.)

 

https://wootool.tistory.com/83

 

[백준][1520번][DP] 내리막길

내리막길 https://www.acmicpc.net/problem/1520 <코드> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51..

wootool.tistory.com

 


 전체코드

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int map[501][501];
int visited[501][501];
int M, N;
int dy[] = { -1, 1, 0, 0 };
int dx[] = { 0, 0, -1, 1 };

void visitedInit()
{
	for (int i = 0; i < M; i++)
		for (int j = 0; j < N; j++)
			visited[i][j] = -1;
}

void Input()
{
	cin >> M >> N;
	for (int i = 0; i < M; i++)
	{
		for (int j = 0; j < N; j++)
		{
			cin >> map[i][j];
		}
	}
}

bool inRange(int y, int x)
{
	if (y >= 0 && x >= 0 && y < M && x < N)
		return true;
	return false;
}

int dfs(int y, int x)
{
	//목적지 도착
	if (y == M - 1 && x == N - 1)
		return 1;
	//이미 도착점에 도착했던 경로가 있을때
	if (visited[y][x]!=-1)
		return visited[y][x];
	
	visited[y][x] = 0;
	for (int i = 0; i < 4; i++)
	{
		int ny = y + dy[i];
		int nx = x + dx[i];
		if (inRange(ny, nx) == false)
			continue;
		//항상 더 낮은 지점으로만 움직일수 있다.
		if (map[y][x] <= map[ny][nx])
			continue;

		visited[y][x] += dfs(ny, nx);
	}

	return visited[y][x];
}

int main()
{
	Input();
	visitedInit();
	cout << dfs(0, 0);

	return 0;
}

 후기

 비슷한 카카오 문제를 풀어본적 있는데 그것과는 다른 방식으로 문제를 풀었다. 

반응형

'알고리즘 문제풀이' 카테고리의 다른 글

백준 10942번 _ 팰린드롬?  (0) 2020.05.05
백준 7579번 _ 앱  (0) 2020.05.05
백준 11049번 _ 행렬 곱셈 순서  (0) 2020.05.04
백준 11066번 _ 파일 합치기  (1) 2020.05.04
백준 2293번 _ 동전 1  (0) 2020.05.03
Comments