본문 바로가기
코딩테스트!(프로그래머스 & 백준)/프로그래머스-C++

코딩테스트 -- 등굣길 - (프로그래머스 / C++)

by Lee_story_.. 2022. 7. 7.
728x90

문제!

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr


문제 설명

계속되는 폭우로 일부 지역이 물에 잠겼습니다. 물에 잠기지 않은 지역을 통해 학교를 가려고 합니다. 집에서 학교까지 가는 길은 m x n 크기의 격자모양으로 나타낼 수 있습니다.

아래 그림은 m = 4, n = 3 인 경우입니다.

프로그래머스!

가장 왼쪽 위, 즉 집이 있는 곳의 좌표는 (1, 1)로 나타내고 가장 오른쪽 아래, 즉 학교가 있는 곳의 좌표는 (m, n)으로 나타냅니다.

격자의 크기 m, n과 물이 잠긴 지역의 좌표를 담은 2차원 배열 puddles이 매개변수로 주어집니다. 오른쪽과 아래쪽으로만 움직여 집에서 학교까지 갈 수 있는 최단경로의 개수를 1,000,000,007로 나눈 나머지를 return 하도록 solution 함수를 작성해주세요.

제한사항
  • 격자의 크기 m, n은 1 이상 100 이하인 자연수입니다.
    • m과 n이 모두 1인 경우는 입력으로 주어지지 않습니다.
  • 물에 잠긴 지역은 0개 이상 10개 이하입니다.
  • 집과 학교가 물에 잠긴 경우는 입력으로 주어지지 않습니다.

 


 

요약하면

 

현재위치 1,1 에서 학교 m,n까지 이동할껀데  여기서 최단경로의 개수 구하라는 문제!

 

 

저는 바로 탐색을 생각하고 재귀를 돌려보았습니다.....

 

 

결과는 정확성 테스트는 모두 통과!!

but 효율성테스트는.... 모두 시간초과....

#include <string>
#include <vector>

#include <iostream>
using namespace std;

int count_way=0;///경우의수

void find(vector<vector<int>> &map,int x, int y,int count, int &min_num){
    if(map[x][y]==1){
        return;
    }
    else if(x==map.size()-1 and y==map[0].size()-1){//도착
        
        if(min_num>count){
            min_num=count;
            count_way=1;
        }
        else if(min_num==count){
            count_way+=1;
        }
    }
    else{
        if(y!=map[0].size()-1){//우
            find(map,x, y+1,count+1,min_num);
        }
        if(x!=map.size()-1){//아래
            find(map,x+1, y,count+1,min_num);
        }
    }
    
}

int solution(int m, int n, vector<vector<int>> puddles) {
    int answer = 0;
    vector<vector<int>> map(n+1,vector<int>(m+1));//전체맵
    int min_num=200;///최솟값
    
    for(vector<int> i : puddles){// 웅덩이
        map[i[1]][i[0]]=1;
    }
    
    find(map,1, 1, 0, min_num);
    
    return count_way%1000000007;
}

이 문제에선 동적계획법 메모이제이션이 필요한 문제인것같네요... 

 

 

 

제가 위에서 재귀로 모든 경우를 탐색했다면 이 방법은 모든 경우를 한번씩 지나가며

a부터 c까지의 최단경로를 따로 저장해두고 c부터 이동할 경우를 탐색을 따로 하는 방법....!

 

(ex ) (a b c), (b a c), (b c) 등 c를 가는 방법은 많은데 여기서 c 다음을 이동할때!

 

재귀는 다시 모든 경우를 탐색하지만

메모제이션은? 최소경로를 + 해주며 그 이후 탐색을 이어나갑니다!!!!!) 매우 중요한 부분인 것 같네요

 

 

 

 

 

그래서! 다음 방법 시작!

 

 

전체 맵 배열을 선언해주는데 여기에는 현재 좌표까지 올 수있는 경우의 수가 추가될것입니다!

int dp[101][101]; // 전체 맵 배열

 

 

시작점은 1로 선언해주고 물웅덩이를 표시해 줍시다.

dp[1][1]=1;//시작점

    for (int i = 0; i < puddles.size(); i++) { 
        dp[puddles[i][1]][puddles[i][0]] = -1;//물웅덩이 X,Y ..... 배열의 행열과 다름...
    }

 

 

이제 여기서 맵 배열을 채워줄껀데 물웅덩이칸은 무시해주시고 비어있는장소에 체크를 해줍시다!

for(int i=1; i<=n;i++){
        for(int j=1; j<=m; j++){
            int a=0;
            int b=0;
            
            if(dp[i][j]==-1){//웅덩이일때는 구할필요 없
                continue;
            }
                
            if(dp[i-1][j]!=-1){//각자리의 경우의수 추가(+위)
                a= dp[i-1][j];
            }
                
            if(dp[i][j-1]!=-1){//각자리의 경우의수 추가(+왼)
                b= dp[i][j-1];
            }
                
            dp[i][j]+=(a+b)%1000000007;// 계속 추가
        }
    }

현재 이동방향이 오른쪽과 아래쪽으로만 움직이기에 

지금 블록의 위와 왼쪽의 경우의 수를 더해주면 현재칸까지의 경우의수를 구할수 있죠!

 

 

return dp[n][m];

그리고나서 마지막 M,N을 출력....

 

오히려 더 쉽네요 

재귀는 생각할게 좀 있는데 이건 단순 이중 FOR문으로 해결가능했습니다.... 

 

오늘도 하나배웠네요!

 

*ALL

#include <string>
#include <vector>
using namespace std;
    int dp[101][101];
int solution(int m, int n, vector<vector<int>> puddles) {
    dp[1][1]=1;//시작점

    for (int i = 0; i < puddles.size(); i++) { 
        dp[puddles[i][1]][puddles[i][0]] = -1;//물웅덩이 X,Y ..... 배열의 행열과 다름...
    }
    for(int i=1; i<=n;i++){
        for(int j=1; j<=m; j++){
            int a=0;
            int b=0;
            
            if(dp[i][j]==-1){//웅덩이일때는 구할필요 없
                continue;
            }
                
            if(dp[i-1][j]!=-1){//각자리의 경우의수 추가(+위)
                a= dp[i-1][j];
            }
                
            if(dp[i][j-1]!=-1){//각자리의 경우의수 추가(+왼)
                b= dp[i][j-1];
            }
                
            dp[i][j]+=(a+b)%1000000007;// 마지막 도착지...
        }
    }

    return dp[n][m];
}

 

 

 

 

틀린점이 있다면 댓 달아주세요!

댓글