본문 바로가기

Algorithm/Baekjoon BOJ

[백준][C++] 1520: 내리막 길

반응형

 

 

 

 

 

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

 

1520번: 내리막 길

여행을 떠난 세준이는 지도를 하나 구하였다. 이 지도는 아래 그림과 같이 직사각형 모양이며 여러 칸으로 나뉘어져 있다. 한 칸은 한 지점을 나타내는데 각 칸에는 그 지점의 높이가 쓰여 있으

www.acmicpc.net

 

 

 

 


- 문제

 

  2차원 배열이 있고, 상하좌우로 숫자가 작은 곳으로만 움직일 수 있다고 할 때 가장 우측하단에 도착할 수 있는 경우의 수를 구하는 문제다.

 

 


- 해설

1. (틀린 방법)

 

일반적인 dfs 방법으로 하나의 점에서 상하좌우를 확인하고 해당 조건에 맞으면 가장 우측하단에 있는 지점에 도착하는 경우의 수를 구하는 방법을 생각해봤다.

 

- 이동이 중복되는 경우도 있고, 경우의 수가 너무 많아서 시간초과가 남

 

 

2. (맞은 방법)

 

dfs(깊이우선탐색)이랑 dp(동적계획)을 같이 사용해보았다.

 

1) dp 배열은 -1로 초기화한다.(어느 지점에서 정답으로 가는 방법이 0가지 방법일 경우에 0이 겹칠 수 있으므로 -1이든 -1021이든 초기화)

 

2) 이미 dp가 저장된 곳이면 바로 반환하고 가장 우측하단의 경우에만 1을 반환한다.

 

3) 이러면 (0,0)에서 move 함수를 시작했어도 채워지는 dp배열은 가장 우측하단부터 채워질 것 같다.

 

 

 


- 풀이

#include <iostream>
#include <vector>
using namespace std;

int M, N, answer = 0;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int board[500][500];

void move(int m, int n){
    int newM, newN;
    if(M == m + 1 && N == n + 1){
        answer++;
    }
    for(int i = 0; i < 4; i++){
        newM = m + dx[i], newN = n + dy[i];
        if(newM >= 0 || newM < M || newN >= 0 || newN < N){
            if(board[m][n] > board[newM][newN]){
                move(newM,newN);    
            }
        }
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    cin >> M >> N;
    
    for(int i = 0; i < M; i++){
        for(int j = 0;j < N; j++){
            cin >> board[i][j];
        }
    }
    move(0,0);
    cout << answer;

    return 0;
}

 

 

#include <iostream>
using namespace std;

int M, N, answer;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int board[501][501];
int dp[501][501];  

int move(int m, int n){
    if(M == m + 1 && N == n + 1){
        return 1;               // 도착했으니 1을 더해주기
    }
    if(dp[m][n] != -1){
        return dp[m][n];        // 이미 도착했던 곳이면 그대로 반환
    }
    dp[m][n] = 0;
    for(int i = 0; i < 4; i++){
        int newM = m + dx[i];
        int newN = n + dy[i];
        if(newM >= 0 && newM < M && newN >= 0 && newN < N){
            if(board[m][n] > board[newM][newN]){
                dp[m][n] = dp[m][n] + move(newM,newN);
            }       // [M][N]부터 역으로 숫자를 세기면서 옴
        }
    }
    return dp[m][n];
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    cin >> M >> N;
    
    for(int i = 0; i < M; i++){
        for(int j = 0;j < N; j++){
            cin >> board[i][j];
            dp[i][j] = -1;              // visited 대신에 -1, 0으로 해놓으면 해당 위치에 접할 수 없는 경우랑 겹침
        }
    }
    answer = move(0,0);
    cout << answer;
    

    return 0;
}

 

 


- 새롭게 알게 된 점

 

반응형

'Algorithm > Baekjoon BOJ' 카테고리의 다른 글

[백준][C++] 9935: 문자열 폭탄  (1) 2022.12.30
[백준][C++] 2629: 양팔저울  (0) 2022.12.30
[백준][C++] 1063: 킹  (1) 2022.12.27
[백준][C++] 2293: 동전 1  (1) 2022.12.26
[백준][C++] 23757: 아이들과 선물 상자  (0) 2022.12.13