코딩/백준 문제 풀이

BOJ 1520 - 내리막 길

stonejjun 2020. 1. 24. 03:21

문제 태그 : https://www.acmicpc.net/problem/1520

문제 설명

문제 풀이 (사고의 흐름)

(1,1)에서 (n,m)으로 갈 수 있는 경우의 수 찾기. 경우의 수를 찾는 것이고, 어떤 칸까지 갈 수 있는 경우의 수는 그 칸으로 올 수 있는 경우의 수의 합으로 표현된다. 따라서 이 문제는 2차원 DP로 해결 할 수 있다.
2차원 필드에서 진행되는 보통의 간단한 DP 문제 같은 경우에는 오른쪽 혹은 아래로 밖에 움직이지 못한다. 따라서 (i,j)는 (i-1,j)와 (i,j-1)로 표현이 된다. 하지만 이 문제는 그렇지 않다. 어떤 (i,j)의 칸으로 올 수 있는 칸은 주위의 4칸 중 (i,j)보다 숫자가 큰 칸이다. 따라서 (i,j)에 대한 경우의 수를 확실하게 구하기 위해서는 주변에 있는 칸들 중 칸의 값이 더 큰 칸에 대한 경우의 수를 모두 알고 있어야 한다. 
이를 해결하기 위해서 DP 테이블을 배열 값이 가장 큰 값부터 채워나가면 된다. 그러면 어떤 칸의 값을 구하기 위한 정보를 얻을 수 있다. 잊으면 안된다. DP식이 성립하기 위해서는 어떤 칸의 식에 들어갈 요소들이 확실히 알고있는 값이어야한다.
아무튼 DP테이블의 크기는 O(N^2) 한 칸당 걸리는 시간복잡도는 상수이므로 총 시간복잡도 O(N^2)에 문제를 해결할 수 있다.

코드 

 

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
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
 
struct poi{
    ll row,col,val;
};
bool sf(poi a,poi b)
{
    return a.val>b.val;
}
poi dat[505050];
ll arr[505][505];
ll dp[505][505];
 
int main()
{
    ll i,j,k,l,m,n,a,b,c,cnt=0;
    scanf("%lld %lld",&n,&m);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            scanf("%lld",&k);
            arr[i][j]=k;
            cnt++;
            dat[cnt].val=k;
            dat[cnt].row=i;
            dat[cnt].col=j;
        }
    sort(dat+1,dat+1+cnt,sf);
    for(i=1;i<=cnt;i++)
    {
        ll r=dat[i].col;
        ll c=dat[i].row;
        if(r==1&&c==1)
        {
            dp[1][1]=1;
            continue;
        }
        if(arr[c][r]!=arr[c-1][r]) dp[c][r]+=dp[c-1][r];
        if(arr[c][r]!=arr[c+1][r]) dp[c][r]+=dp[c+1][r];
        if(arr[c][r]!=arr[c][r-1]) dp[c][r]+=dp[c][r-1];
        if(arr[c][r]!=arr[c][r+1]) dp[c][r]+=dp[c][r+1];
    }
    printf("%lld",dp[n][m]);    
}
cs

'코딩 > 백준 문제 풀이' 카테고리의 다른 글

BOJ 17955 - Max or Min  (0) 2020.02.17
BOJ 1006 - 습격자 초라기  (0) 2020.02.09
BOJ 4243 - 보안 업체  (0) 2019.12.03
BOJ 1848 - 동굴 탐험  (0) 2019.11.25
BOJ 1753 - 최단경로  (0) 2019.11.24