알고리즘/알고리즘 공부 내용 정리

백준 BOJ 풀이 : BFS 문제들 위주 풀이 (그래프 탐색) 220725

restudy 2022. 7. 25. 09:30
반응형

백준 BOJ 5017번 : 마니또

문제 난이도 : Silver I

알고리즘 분류 : 해시를 사용한 집합과 맵, 그래프 이론

 

N개의 이름 쌍이 주어질 때, 쌍을 연결하면서 생기는 고리의 수를 구하는 문제이다.

 

우선 입력이 번호가 아닌 이름으로 주어지므로 해시를 사용한 집합과 맵을 활용해야 한다.

그 다음 고리의 형성은 여러 가지로 판단이 가능하겠지만, 나는 나한테 익숙한 방법인 분리 집합을 활용했다.

간선을 하나씩 추가하다가 두 이름이 같은 그룹에 속한 이름이라면, 간선을 연결하면서 새로운 고리가 하나 생기게 된다.

이런 식으로 카운트 해줘서 답을 구해주면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

vector<int> v;

int f(int x) {
    if(x == v[x]) return x;
    else return v[x] = f(v[x]);
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    for(int t=1; ; t++) {
        int N; cin >> N;
        if(N == 0) break;

        v.resize(N*2);
        for(int i=0; i<v.size(); i++) v[i] = i;

        map<string, int> m;
        vector<string> u;
        int cnt = 0, ans = 0;

        for(int i=0; i<N; i++) {
            string a, b; cin >> a >> b;

            bool check = false;
            for(int j=0; j<u.size(); j++)
                if(a == u[j]) check = true;
            if(!check) {
                u.push_back(a);
                m[a] = cnt++;
            }

            check = false;
            for(int j=0; j<u.size(); j++)
                if(b == u[j]) check = true;
            if(!check) {
                u.push_back(b);
                m[b] = cnt++;
            }

            if(f(m[a]) == f(m[b])) ans++;
            else v[f(m[a])] = f(m[b]);
        }

        cout << t << " " << ans << "\n";
    }
}

 

 

백준 BOJ 16021번 : Choose your own path

문제 난이도 : Silver II

알고리즘 분류 : 그래프 탐색

 

N개의 책 페이지 각각이 다른 페이지로 갈 수 있는 연결이 있을 때, 1쪽부터 시작해서 모든 페이지에 다 도달할 수 있는지의 여부와 가장 페이지 방문이 적은 루트의 페이지 수를 구하는 문제이다.

 

그래프 연결과 탐색을 통해 풀이해줄 수 있다.

특히 가장 짧은 루트의 길이는 연결된 간선이 더 이상 없는 노드들의 거리 중 최솟값을 구해주면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

vector<vector<int>> adj;
vector<int> dis;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin >> N;

    adj.resize(N+1);

    for(int i=1; i<=N; i++) {
        int M; cin >> M;

        while(M--) {
            int x; cin >> x;

            adj[i].push_back(x);
        }
    }

    dis.resize(N+1, -1);
    dis[1] = 1;

    queue<int> q;
    q.push(1);

    int ans = INT_MAX;

    while(!q.empty()) {
        int x = q.front();
        q.pop();

        for(int i=0; i<adj[x].size(); i++) {
            int y = adj[x][i];

            if(dis[y] != -1) continue;

            dis[y] = dis[x] + 1;
            q.push(y);
        }

        if(adj[x].size() == 0) ans = min(ans, dis[x]);
    }

    bool check = true;

    for(int i=1; i<=N; i++)
        if(dis[i] == -1) check = false;

    if(check) cout << "Y\n";
    else cout << "N\n";

    cout << ans << "\n";
}

 

 

백준 BOJ 4191번 : Dominos 2

문제 난이도 : Silver II

알고리즘 분류 : 그래프 탐색 (DFS, BFS)

 

도미노의 수, 어떤 도미노가 쓰러졌을 때 쓰러지는 다른 도미노의 번호, 그리고 처음에 쓰러뜨릴 도미노들의 번호가 주어질 때 총 쓰러지는 도미노의 개수를 구하는 문제이다.

 

도미노 각각을 노드로 보고 연쇄적으로 쓰러지는 도미노 쌍들을 간선으로 연결해준 뒤 그래프 탐색을 통해 도달 가능한 정점들의 수를 구해주면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

vector<vector<int>> adj;
vector<bool> vis;

void f(int x) {
    vis[x] = true;

    for(int i=0; i<adj[x].size(); i++) {
        int y = adj[x][i];

        if(!vis[y]) f(y);
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin >> T;

    while(T--) {
        int N, M, K; cin >> N >> M >> K;

        adj.clear();
        adj.resize(N+1);

        while(M--) {
            int a, b; cin >> a >> b;

            adj[a].push_back(b);
        }

        vis.clear();
        vis.resize(N+1);

        while(K--) {
            int x; cin >> x;

            if(!vis[x]) f(x);
        }

        int ans = 0;
        for(int i=1; i<=N; i++)
            if(vis[i]) ans++;

        cout << ans << "\n";
    }
}

 

 

백준 BOJ 9205번 : 맥주 마시면서 걸어가기

문제 난이도 : Silver I

알고리즘 분류 : 그래프 탐색

 

문제 상황이 조금 복잡한데, 요약해서 설명하면 맨해튼 거리가 1,000 이하인 지점 사이만 이동이 가능할 때 출발점에서 도착점까지 이동할 수 있는지의 여부를 구하는 문제이다.

 

출발점, 도착점, 편의점들을 각각 하나의 노드라고 생각하고 서로 이동이 가능한 정점 사이에 간선을 만들어주자.

이제 0번 노드(출발점)에서 그래프 탐색을 통해 N+1번 노드(도착점)로 도달할 수 있는지의 여부를 판별해주면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

vector<vector<int>> adj;
vector<bool> vis;

void f(int x) {
    vis[x] = true;

    for(int i=0; i<adj[x].size(); i++) {
        int y = adj[x][i];

        if(!vis[y]) f(y);
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin >> T;

    while(T--) {
        int N; cin >> N;

        adj.clear();
        adj.resize(N+2);

        vector<pair<int, int>> v(N+2);
        for(int i=0; i<v.size(); i++) cin >> v[i].first >> v[i].second;

        for(int i=0; i<v.size(); i++)
            for(int j=0; j<v.size(); j++) {
                if(j == 0 || i == N+1) continue;
                if(i == j) continue;

                if(abs(v[i].first - v[j].first) + abs(v[i].second - v[j].second) > 1000) continue;

                adj[i].push_back(j);
            }

        vis.clear();
        vis.resize(N+2);

        f(0);

        if(vis[N+1]) cout << "happy\n";
        else cout << "sad\n";
    }
}

 

 

백준 BOJ 14562번 : 태권왕

문제 난이도 : Silver II

알고리즘 분류 : BFS

 

a와 b가 주어질 때 a*2, b+3의 연산 또는 a+1, b의 연산으로 a와 b를 같게 만든다고 할 때 그 최소 연산 횟수를 구하는 문제이다.

 

a와 b의 초깃값이 둘 다 100 이하이므로 적절히 1,000 이하의 범위에서 최소 이동이 나올 것이라고 생각하고 BFS를 사용하여 풀었다.

2차원 배열을 선언하여 (a, b) 순서쌍이 둘이 같아지는 최초 지점까지 방문하는 거리를 구하면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin >> T;

    while(T--) {
        int a, b; cin >> a >> b;

        vector<vector<int>> dis(1000, vector<int>(1000, -1));
        dis[a][b] = 0;

        queue<pair<int, int>> q;
        q.push({a, b});

        while(!q.empty()) {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();

            if(x == y) {
                cout << dis[x][y] << "\n";
                break;
            }

            if(x*2 < 1000 && y+3 < 1000 && dis[x*2][y+3] == -1) {
                dis[x*2][y+3] = dis[x][y] + 1;
                q.push({x*2, y+3});
            }
            if(x+1 < 1000 && dis[x+1][y] == -1) {
                dis[x+1][y] = dis[x][y] + 1;
                q.push({x+1, y});
            }
        }
    }
}

 

 

백준 BOJ 12523번 : Twibet (Small), 백준 BOJ 12524번 : Twibet (Large)

문제 난이도 : Silver II

알고리즘 분류 : 그래프 탐색

 

N명의 승려가 있고 각 승려는 다른 특정 번호의 승려가 나갈 경우 따라 나간다고 할 때, i번 승려가 처음 나갈 때 나가게 되는 승려의 수를 모든 i에 대하여 구하는 문제이다.

 

그래프 탐색으로 해결할 수 있는 문제로, a번 승려가 나갈 때 b번 승려가 따라나간다면 a번 노드에서 b번 노드로 이동하는 간선을 만들어 줄 수 있다.

그런 뒤 i번째 승려가 먼저 나가는 경우, i번 노드에서 탐색을 시작하여 도달할 수 있는 모든 노드의 수를 구하면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

vector<vector<int>> adj;
vector<bool> vis;

void f(int x) {
    vis[x] = true;

    for(int i=0; i<adj[x].size(); i++) {
        int y = adj[x][i];

        if(!vis[y]) f(y);
    }
}

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin >> T;

    for(int t=1; t<=T; t++) {
        cout << "Case #" << t << ":\n";

        int N; cin >> N;

        adj.clear();
        adj.resize(N+1);

        for(int i=1; i<=N; i++) {
            int x; cin >> x;

            adj[x].push_back(i);
        }

        for(int i=1; i<=N; i++) {
            vis.clear();
            vis.resize(N+1);

            f(i);

            int ans = 0;
            for(int i=1; i<=N; i++)
                if(vis[i]) ans++;

            cout << ans << "\n";
        }
    }
}

 

 

백준 BOJ 18232번 : 텔레포트 정거장

문제 난이도 : Silver II

알고리즘 분류 : BFS

 

M개의 텔레포트로 좌표를 이동하거나, +1 또는 -1씩 이동하여 시작점에서 도착점까지 이동하는 가장 최소 이동 수를 구하는 문제이다.

 

간단한 BFS 문제로, 매 이동마다 모든 텔레포트와 +1, -1 좌표 이동을 검사해주면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    int sour, dest; cin >> sour >> dest;

    vector<vector<int>> adj(N+1);

    while(M--) {
        int a, b; cin >> a >> b;

        adj[a].push_back(b);
        adj[b].push_back(a);
    }

    vector<int> dis(N+1, -1);
    dis[sour] = 0;

    queue<int> q;
    q.push(sour);

    while(!q.empty()) {
        int x = q.front();
        q.pop();

        if(x == dest) {
            cout << dis[dest] << "\n";
            break;
        }

        for(int i=0; i<adj[x].size(); i++) {
            int y = adj[x][i];

            if(dis[y] != -1) continue;

            dis[y] = dis[x] + 1;
            q.push(y);
        }

        if(x-1 > 0 && dis[x-1] == -1) {
            dis[x-1] = dis[x] + 1;
            q.push(x-1);
        }
        if(x+1 <= N && dis[x+1] == -1) {
            dis[x+1] = dis[x] + 1;
            q.push(x+1);
        }
    }
}

 

 

백준 BOJ 1326번 : 폴짝폴짝

문제 난이도 : Silver II

알고리즘 분류 : BFS

 

개구리가 1 ~ N 중 출발점에서 시작하여 현재 서 있는 위치의 배열값의 배수만큼 이동할 수 있다고 할 때, 도착점까지 최소 이동 횟수를 구하는 문제이다.

 

간단한 BFS 문제로, 범위 내에서 모든 배열 값의 배수 거리만큼 큐에 넣으면서 거리를 구하면 된다.

도착점에 도달할 경우 바로 거리 출력 후 종료해주면 되고 그렇지 못할 경우 -1을 출력하면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin >> N;

    vector<int> v(N+1);
    for(int i=1; i<=N; i++) cin >> v[i];

    int sour, dest; cin >> sour >> dest;

    vector<int> dis(N+1, -1);
    dis[sour] = 0;

    queue<int> q;
    q.push(sour);

    while(!q.empty()) {
        int x = q.front();
        q.pop();

        if(x == dest) {
            cout << dis[x] << "\n";
            return 0;
        }

        for(int i=1; i<=N; i++) {
            if(abs(x - i) % v[x] != 0) continue;
            if(dis[i] != -1) continue;

            dis[i] = dis[x] + 1;
            q.push(i);
        }
    }

    cout << -1 << "\n";
}

 

 

백준 BOJ 21736번 : 헌내기는 친구가 필요해

문제 난이도 : Silver II

알고리즘 분류 : BFS

 

I는 출발 위치, X는 벽, P는 사람이라고 할 때 벽을 만나지 않고 만날 수 있는 사람들의 수를 구하는 문제이다.

 

정석적인 BFS 문제로, 몇 가지 조건문만 수정해주면 정답을 받을 수 있다.

항상 느끼는 거지만 BFS 문제는 문제 난이도에 비해 코드가 길어서 빨리 풀기 번거로운 것 같다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<vector<bool>> vis(N, vector<bool>(M));
    queue<pair<int, int>> q;

    vector<vector<char>> v(N, vector<char>(M));
    for(int i=0; i<N; i++)
        for(int j=0; j<M; j++) {
            cin >> v[i][j];

            if(v[i][j] == 'I') {
                vis[i][j] = true;
                q.push({i, j});
            }
        }

    int ans = 0;

    while(!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();

        int dx[4] = {1, -1, 0, 0};
        int dy[4] = {0, 0, 1, -1};

        for(int i=0; i<4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
            if(vis[nx][ny] || v[nx][ny] == 'X') continue;

            if(v[nx][ny] == 'P') ans++;

            vis[nx][ny] = true;
            q.push({nx, ny});
        }
    }

    if(ans > 0) cout << ans << "\n";
    else cout << "TT\n";
}

 

 

백준 BOJ 7107번 : Journy of A Knight

문제 난이도 : Silver II

알고리즘 분류 : BFS

 

체스판의 크기와 도착 좌표가 주어질 때, 나이트가 (1, 1)에서 출발하여 도착 지점까지 이동하는데 필요한 최소 이동 횟수를 구하는 문제이다.

 

정석적인 BFS 문제로, 나이트의 이동 방식 8가지를 모두 검사하면서 거리를 기록해주면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    int a, b; cin >> a >> b;

    vector<vector<int>> dis(N+1, vector<int>(M+1, -1));
    dis[1][1] = 0;

    queue<pair<int, int>> q;
    q.push({1, 1});

    while(!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();

        if(x == a && y == b) {
            cout << dis[x][y] << "\n";
            return 0;
        }

        int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
        int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};

        for(int i=0; i<8; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx <= 0 || ny <= 0 || nx > N || ny > M) continue;
            if(dis[nx][ny] != -1) continue;

            dis[nx][ny] = dis[x][y] + 1;
            q.push({nx, ny});
        }
    }

    cout << "NEVAR\n";
}

 

 

백준 BOJ 14651번 : 걷다보니 신천역 삼 (Large)

문제 난이도 : Silver I

알고리즘 분류 : DP

 

0, 1, 2로만 구성된 N자리 자연수 중 3의 배수가 몇 개인지 구하는 문제이다.

 

3의 배수는 모든 자릿수의 합이 3의 배수이면 된다.

dp를 이용하여 풀기 위해, dp[i][j]를 i자리이면서 자릿수의 합을 3으로 나눈 나머지가 j인 수의 개수라고 하자.

그러면 dp[i][0] = dp[i][1] = dp[i][2] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2]이다. (점화식이 모두 같다.)

다만 0은 자연수가 아니므로, dp[1][i]의 값은 각각 0, 1, 1이다.

이제 점화식을 가지고 반복문으로 답을 구해주면 된다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int dp[33334][3] = {{}, {0, 1, 1}};
    int mod = 1e9 + 9;

    for(int i=2; i<=33333; i++) {
        dp[i][0] = (dp[i-1][0] + dp[i-1][1] + dp[i-1][2]) % mod;
        dp[i][1] = (dp[i-1][0] + dp[i-1][1] + dp[i-1][2]) % mod;
        dp[i][2] = (dp[i-1][0] + dp[i-1][1] + dp[i-1][2]) % mod;
    }

    int N; cin >> N;

    cout << dp[N][0] << "\n";
}

 

 

백준 BOJ 2885번 : 초콜릿 식사

문제 난이도 : Silver II

알고리즘 분류 : 그리디

 

2의 배수 길이의 초콜릿을 사서, 초콜릿을 반으로 쪼개는 과정을 거쳐 원하는 길이의 합을 만든다고 할 때 사야하는 초콜릿의 길이와 쪼개는 최소 횟수를 구하는 문제이다.

 

원하는 길이를 2진수로 나타냈을 때 1에 해당하는 값들만 취하면 된다.

예를 들어 길이 6을 원한다면, 그보다 크거나 같은 2의 거듭제곱 중 가장 작은 8짜리 초콜릿을 사서, 6이 2진수로 110이므로 8짜리를 반으로 쪼개면서 4, 2에 해당하는 길이만 취하면 된다.

이것은 길이를 2진수로 나타내었을 때 가장 마지막으로 나오는 1의 위치가 쪼개는 횟수의 정답이 된다.

위에서 예시로 든 6의 경우, 사야할 초콜릿의 길이는 8이 되고 쪼개는 횟수는 2가 된다.

 

반례가 존재하는데 바로 원하는 길이가 애초부터 2의 거듭제곱인 경우이다.

이 경우는 초콜릿을 나누는 횟수가 0이 되어야 한다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int x; cin >> x;

    string str = "";

    while(x > 0) {
        str = char(x % 2 + '0') + str;

        x /= 2;
    }

    int cur = str.length() - 1;
    while(str[cur] == '0') cur--;

    int a = pow(2, str.length());
    int b = cur + 1;

    if(b == 1) {
        a /= 2;
        b--;
    }

    cout << a << " " << b << "\n";
}

 

 

백준 BOJ 9753번 : 짝 곱

문제 난이도 : Silver II

알고리즘 분류 : 에라토스테네스의 체

 

10만 이하의 수 K에 대해, K 이상의 서로 다른 두 소수의 곱 중 최솟값을 구하는 문제이다.

 

더 좋은 풀이가 있을 것인데, 그냥 가장 먼저 떠오르는 풀이로 풀었다.

10만 이상이면서 두 소수의 곱인 값으로 가장 쉬운 것은 2 * 50021 = 100042가 있다. (이건 직접 코드를 짜서 5만 이상이면서 5만과 가장 가까운 소수를 찾으면 된다.)

그래서 두 소수의 곱이 100042 이하인 조합들을 모두 벡터에 저장하고, 정답을 이 벡터에서 이분 탐색으로 찾아주는 방식을 이용했다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector<bool> prime(50022, true);
    prime[1] = false;
    for(int i=2; i*i<=50021; i++)
        for(int j=2; i*j<=50021; j++) prime[i*j] = false;

    vector<int> v;
    for(int i=2; i<=50021; i++)
        if(prime[i]) v.push_back(i);

    vector<int> u;
    for(int i=0; i<v.size(); i++)
        for(int j=i+1; j<v.size(); j++) {
            if(v[i] * v[j] > 100042) break;
            u.push_back(v[i]*v[j]);
        }

    sort(u.begin(), u.end());
    u.erase(unique(u.begin(), u.end()), u.end());

    int T; cin >> T;

    while(T--) {
        int x; cin >> x;

        cout << u[lower_bound(u.begin(), u.end(), x) - u.begin()] << "\n";
    }
}

 

 

백준 BOJ 15242번 : Knight

문제 난이도 : Silver I

알고리즘 분류 : BFS

 

체스판에서 두 좌표가 주어질 때, 첫 번째 좌표에서 두 번째 좌표로 나이트를 이동하여 도달하는 최소 이동 횟수를 구하는 문제이다.

 

간단한 BFS 문제이고, 나이트의 8가지 이동 방식을 배열에 저장하여 탐색해주면 된다.

기존 나이트 문제랑 다른 점은 좌표가 숫자가 아닌 문자 + 숫자로 이루어지는 정도뿐이다.

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    string a, b; cin >> a >> b;

    int bx = a[0] - 'a' + 1, by = a[1] - '0';
    int ex = b[0] - 'a' + 1, ey = b[1] - '0';

    vector<vector<int>> dis(9, vector<int>(9, -1));
    dis[bx][by] = 0;

    queue<pair<int, int>> q;
    q.push({bx, by});

    while(!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();

        if(x == ex && y == ey) {
            cout << dis[ex][ey] << "\n";
            break;
        }

        int dx[8] = {-2, -2, -1, 1, 2, 2, 1, -1};
        int dy[8] = {-1, 1, 2, 2, 1, -1, -2, -2};

        for(int i=0; i<8; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx <= 0 || ny <= 0 || nx > 8 || ny > 8) continue;
            if(dis[nx][ny] != -1) continue;

            dis[nx][ny] = dis[x][y] + 1;
            q.push({nx, ny});
        }
    }
}

 

 

백준 BOJ 14996번 : 그대, 그머가 되어

문제 난이도 : Silver I

알고리즘 분류 : BFS

 

M개의 치환 가능한 숫자 쌍이 있을 때, 특정 숫자에서 다른 숫자로 바꾸는데 필요한 최소 치환 횟수를 구하는 문제이다.

 

각 숫자를 노드 번호로 보고, 치환 가능한 숫자 사이의 관계를 간선으로 보면 그래프가 되고 시작 번호에서 도착 번호까지의 BFS를 수행하여 최단 거리를 구하면 답이 된다.

이 때 치환 가능한 두 수 (x, y)란 x에서 y로 치환이 되는 것뿐만 아니라 y에서 x로도 치환이 된다는 사실에 유의하자. (양방향 간선을 연결해주어야 한다.)

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int sour, dest; cin >> sour >> dest;

    int N, M; cin >> N >> M;

    vector<vector<int>> adj(N+1);

    while(M--) {
        int a, b; cin >> a >> b;

        adj[a].push_back(b);
        adj[b].push_back(a);
    }

    vector<int> dis(N+1, -1);
    dis[sour] = 0;

    queue<int> q;
    q.push(sour);

    while(!q.empty()) {
        int x = q.front();
        q.pop();

        if(x == dest) {
            cout << dis[dest] << "\n";
            return 0;
        }

        for(int i=0; i<adj[x].size(); i++) {
            int y = adj[x][i];

            if(dis[y] != -1) continue;

            dis[y] = dis[x] + 1;
            q.push(y);
        }
    }

    cout << -1 << "\n";
}

 

 

 

반응형