[BOJ] 11403 - 경로 찾기

황규빈·2022년 2월 12일
0

알고리즘

목록 보기
23/33

💎 문제


가중치 없는 방향 그래프 G가 주어졌을 때, 모든 정점 (i, j)에 대해서, i에서 j로 가는 경로가 있는지 없는지 구하는 프로그램을 작성하시오.

💎 입력


첫째 줄에 정점의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄부터 N개 줄에는 그래프의 인접 행렬이 주어진다. i번째 줄의 j번째 숫자가 1인 경우에는 i에서 j로 가는 간선이 존재한다는 뜻이고, 0인 경우는 없다는 뜻이다. i번째 줄의 i번째 숫자는 항상 0이다.
ex)
3
0 1 0
0 0 1
1 0 0

💎 출력


총 N개의 줄에 걸쳐서 문제의 정답을 인접행렬 형식으로 출력한다. 정점 i에서 j로 가는 경로가 있으면 i번째 줄의 j번째 숫자를 1로, 없으면 0으로 출력해야 한다.
ex)
1 1 1
1 1 1
1 1 1

💎 풀이 방법


문제의 난이도는 상당히 쉬웠으나 앞으로 나올 수도 있는 유형의 그래프 탐색이기 때문에 개념과 이론을 한번 짚고나가고자 velog에 게시하게 되었다. 문제를 보면 그래프 탐색을 이용한 문제임을 알 수 있고 i번 째 줄의 j번 째 숫자를 확인하여 업데이트 해주는 방식으로 dfs를 활용할 수도 있을 것 같다는 생각과 함께 플로이드-와샬(Floyd-Warshall) 알고리즘을 한번 알아보자!!

그래프에서 정점들이 주어지고 이에 대한 정점끼리의 최단 경로를 구하는 문제들이 자주 나오고 있는데 이에 플로이드-와샬은 모든 정점에서 모든 정점들로의 최단 경로를 구하는 알고리즘이라고 할 수 있다. 인접행렬을 통해서 i에서 j로 가는 경로가 존재함을 표시하였다면 정점에 인접해 있는 정점들을 이동하면서 이러한 경로를 하나씩 업데이트 해주는 것이다!! 따라서 거쳐가는 정점들을 기준으로 반복을 통해서 업데이트 해준다!

    for(int m = 0;m < N;m++){
        for(int i = 0;i < N;i++){
            for(int j = 0;j < N;j++){
                if(v[i][m] && v[m][j]){
                    v[i][j] = 1;
                }
            }
        }
    }

앞서 설명한 대로 거쳐가는 정점을 기준으로 해서 반복을 해줄 것이다. 정점 m을 기준으로 i에서 j로 갈 수 있는 경로를 확인해 준 후 m을 거쳤을 때 존재하는 위치라면 i, j 위치의 경로를 1로 업데이트 해준다!! 이는 거쳐가는 정점의 갯수 만큼 반복, 인접 행렬 크기만큼의 반복문을 통하여 구해준다!

쉬운 문제이지만 가중치와 연관되어 최소의 가중치를 지속적으로 업데이트 해주는 문제가 나올 수 있으니 모든 정점에 대해서 거쳐가는 정점을 기준으로 경로를 찾아주어야할 때 플로이드-와샬을 사용하도록 하자!! 이와 관련된 알고리즘으로 다익스트라와 벨만포드가 있으니 이 둘 또한 알고 있자!!

💎 전체 코드


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

int main(int argc, const char * argv[]) {
  
    cin >> N;
    vector <vector <int>> v(N + 1, vector<int>(N + 1));
    for(int i = 0;i < N;i++){
        for(int j = 0;j < N;j++){
            cin >> v[i][j];
        }
    }
    
    for(int m = 0;m < N;m++){
        for(int i = 0;i < N;i++){
            for(int j = 0;j < N;j++){
                if(v[i][m] && v[m][j]){
                    v[i][j] = 1;
                }
            }
        }
    }
    
    for(int i = 0;i < N;i++){
        for(int j = 0;j < N;j++){
            cout << v[i][j] << " " ;
        }
        cout << "\n";
    }
    
    return 0;
}

💎 고민


이제 방학이 약 2주 정도 남았다,,,시간이 굉장히 빠른데 그 동안 돌아보면 열심히 꾸준히 알고리즘도 풀고 velog에 게시해보면서 복습도 할 수 있어 꽤 많은 것을 얻어갈 수 있는 방학이었다. 남은 기간동안 좀더 꾸준히 풀어보고 프로그래머스 스킬체크 2도 풀어보도록 하자. 이제 남은 기간은 못 풀어봤던 유형의 문제나 내가 익숙해지지 않은 문제를 반복해서 풀고 기억에 남는 문제를 velog에 올려보도록 하겠다!!

화이팅!!

profile
안녕하세욤

0개의 댓글