본문 바로가기

Notice
Recent Posts
Recent Comments
«   2024/11   »
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
Tags
더보기
Archives
관리 메뉴

10164. 격자상의 경로 본문

알고리즘 문제풀기/백준(Acmicpc)

10164. 격자상의 경로

알광(Algwang) 2019. 1. 17. 11:11

문제링크 : https://www.acmicpc.net/problem/10164


< 입력 >


N(세로 사이즈, <=15)


M(가로 사이즈, <=15)


K(경유점, 1개일 경우 번호/0개일 경우 0)


< 출력 >


1번에서 K번을 거쳐 M*N번까지 갈 수 있는 최단경로의 수


< 풀이 >


우선 경로의 수는 int 범위 안에서 수행 가능하지만 "15 * 15밖에 안되네 그냥 int로 하자"라고 생각하면 안된다.


나중에 해보면 알겠지만 입력으로 "15 15 0"이 들어올 경우가 최다 경로인데 40,116,600개가 나온다.


18 * 18이상은 int 범위가 넘어가게 된다.


[ 사이즈만 보고 방심하면 히든 케이스에서 터져버린다. 다른 문제 풀 때도 주의해야할 점 ]


이제 풀이로 들어가보면 아이디어 자체는 간단하다. 중학교 때 수학에서 배운 방법을 사용하는 것이다.



이 맵에서 1번부터 8번을 거쳐 15번까지 가는 최단경로의 수는 (1번부터 8번까지 가는 최단경로의 수) * (8번부터 15번까지 가는 최단경로의 수)이다.




위와 같이 시작점을 기준으로 가로/세로, 경유점을 기준으로 가로/세로의 값을 1로 초기화 시킨다.

다음으로 초기화되지 않은 점의 값을 왼쪽과 위의 값의 합으로 한다.



이렇게 진행하고 나면 위와 같은 그림이 만들어진다.


경유점의 값 3은 시작점에서 경유점까지의 최단경로 수,


도착점의 값 3은 경유점에서 도착점까지의 최단경로 수를 나타낸다.


최종적으로 시작점에서 경유점을 거친 도착점까지의 최단경로 수는 3 * 3 = 9가 된다.


+ 경유점이 0개일 경우는 예외로 처리하여 전체에 대해 같은 과정을 수행해준다.




- 소스 코드 -


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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include<iostream>
/*
 * 중학교 때 수학 시간에 배운 길찾기 방법을 사용했습니다.
 * 점1에서 점2까지의 최단경로의 수를 구하기 위해서
 * 점1의 오른쪽, 아래의 모든 점을 1로 초기화하고
 * 초기화되지 않은 점들 중 가장 왼쪽 위부터 시작해서
 * 자신의 오른쪽 위의 값과의 합을 오른쪽에 씁니다.
 * 즉, dp[i-1][j]+dp[i][j-1]=dp[i][j]가 됩니다.
 * 중단점이 없을 경우와 있을 경우를 구분해서 사용합니다.
 */
using namespace std;
 
int main(void){
    int dp[20][20]={0};
    int m,n,o;
    cin>>n>>m>>o;
    // 입력
    if(o!=0){
        int oI=(o-1)/m;
        int oJ=(o-1)%m;
        int path1=0;
        int path2=0;
        // ㅇ 까지의 경로(path1), ㅇ 이후의 경로(path2)
        for(int i=0;i<=oI;i++){
            dp[i][0]=1;
        }
        for(int j=0;j<=oJ;j++){
            dp[0][j]=1;
        }
        for(int i=oI+1;i<n;i++){
            dp[i][oJ]=1;
        }
        for(int j=oJ+1;j<m;j++){
            dp[oI][j]=1;
        }
        // 시작점의 가로(오른쪽) 세로(아래), ㅇ 의 가로(오른쪽) 세로(아래)를 1로 초기화한다.
        for(int i=1;i<=oI;i++){
            for(int j=1;j<=oJ;j++){
                dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
        }
        path1=dp[oI][oJ];
        // 시작점에서 ㅇ 까지의 1로 초기화 되어있지 않은 구간을 통해 dp를 구한다.
        for(int i=oI+1;i<n;i++){
            for(int j=oJ+1;j<m;j++){
                dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
        }
        path2=dp[n-1][m-1];
        // ㅇ 에서 끝점까지의 초기화 되어있지 않은 구간을 통해 dp를 구한다.
        
        cout<<path1*path2<<endl;
    }else{
        for(int i=0;i<n;i++){
            dp[i][0]=1;
        }
        for(int j=0;j<m;j++){
            dp[0][j]=1;
        }
        // 시작점의 가로(오른쪽) 세로(아래)를 1로 초기화한다.
        for(int i=1;i<n;i++){
            for(int j=1;j<m;j++){
                dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                cout<<dp[i][j]<<" ";
            }
            cout<<endl;
        }
        // ㅇ 가 존재하지 않으므로 시작점부터 끝점까지의 초기화되지 않은 구간을 통해 dp를 구한다.
        cout<<dp[n-1][m-1]<<endl;
    }
}
cs




'알고리즘 문제풀기 > 백준(Acmicpc)' 카테고리의 다른 글

1309.동물원  (0) 2019.01.22
11060. 점프 점프  (0) 2019.01.18
14720. 우유 축제  (0) 2019.01.15
11727. 2×n 타일링 2  (0) 2019.01.15
1967. 트리의 지름  (0) 2019.01.14
Comments