CPP05

JUSTICE_DER·2023년 7월 26일
0

⏲ CPP - 코딩테스트

목록 보기
9/41

https://www.acmicpc.net/problem/2644

1. 2644 - BFS + 경로찾기

= 배열 하나를 더 놓기

2차원 배열의 초기화를 했는데,

이상한 값들이 들어가 있다..

왜????

찾아보니까.. 원래는 배열은 생성하면 0으로 초기화되는데
CPP는 당연히 그렇진 않고,
2차원 배열이라도 int visited[N][N] = {0, };
위처럼 넣으면 0으로 초기화 된다고 보았는데,
왠지 적용이 안되는 모습이다..

CPP 2차원 배열의 0 초기화
https://slaystudy.com/initialize-2d-array-c-to-zero/

위의 글에서 memset을 사용하여 초기화하였다.

시도

#include <iostream>
#include <queue>

#include <cstring>
 
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N;
    cin >> N;

    int A;
    int B;
    cin >> A;
    cin >> B;

    int T;
    cin >> T;

    int connection[N+1][N+1] = {0,}; //적용 안됨
    int visited[N+1][N+1] = {0, };
    memset(connection, 0, sizeof(connection));
    memset(visited, 0, sizeof(visited));

    int from, to;
    for (int i = 0; i < T; i++)
    {
        cin >> from;
        cin >> to;

        connection[from][to] = 1;
        connection[to][from] = 1;
    }

    int count = 0;
    queue<int> nextNode;
    nextNode.push(A);

    while (!nextNode.empty())
    {
        count++;

        int A = nextNode.front();
        nextNode.pop();
        if(A == to)
        {
            break;
        }

        for (int i = 1; i <= N; i++)
        {
            if (connection[A][i] == 1 && visited[A][i] == false)
            {
                visited[A][i] = count;
                visited[i][A] = count;

                nextNode.push(i);
            }
        }
    }

    int min = 100;
    for(int i=0;i<N; i++)
    {
        if((visited[B][i]!=0) && min>visited[B][i])
        {
            min = visited[B][i];
        }
    }

    cout << min << "\n";


    return 0;
}

BFS로 구현을 해보았다
연결된건 알겠고 BFS로 A로부터 B까지 최단거리를 구하긴 했는데,
위의 코드로는 해당 값이 A로부터 간 B의 값인지 알 수가 없었다..

DFS로는 경로를 찾기 쉽고, BFS로는 최단거리를 찾기 쉽다.
https://kk-eezz.tistory.com/23

BFS에서 최단거리를 찾기 위해선,
따로 자료구조를 활용해야만 한다.

BFS로 풀어보자

시도 2

#include <iostream>
#include <queue>
// #include <stack>

#include <cstring>

using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N;
    cin >> N;

    int ans_From;
    int ans_To;
    cin >> ans_From;
    cin >> ans_To;

    bool connection[N + 1][N + 1]; // 적용 안됨
    bool visited[N + 1];           // 2차원배열인 간선이 아닌, 1차원 배열로 정점을 기준으로 하였다.
                                   // 중복된 정점을 통과하지 못하도록 한다.
    memset(connection, false, sizeof(connection));
    memset(visited, false, sizeof(visited));

    int T;
    cin >> T;

    int from, to;
    for (int i = 0; i < T; i++)
    {
        cin >> from;
        cin >> to;

        connection[from][to] = true;
        connection[to][from] = true;
    }

    queue<int> nextNode;
    nextNode.push(ans_From);

    int path[N + 1] = {
        0,
    };
    while (!nextNode.empty())
    {
        int num = nextNode.front();
        nextNode.pop();

        if (num == ans_To)
        {
            break;
        }

        for (int i = 1; i < N + 1; i++)
        {
            if (connection[num][i] && !visited[i])
            {
                visited[num] = true;
                path[i] = num;

                nextNode.push(i);
            }
        }
    }

    //도달하지 못한 경우
    if(path[ans_To]==0)
    {
        cout << -1 << "\n";
        return 0;
    }

    // 역추적

    int i = path[ans_To];
    int count = 0;
    while (true)
    {
        count++;
        if (i != ans_From)
        {
            i = path[i];
        }
        else
        {
            break;
        }
    }

    cout << count <<"\n";
    return 0;
}

7에서 2로 간 경우, 7을 못가도록 visited표시하고,
path[2]에 7을 대입
2에서 1로 간 경우, 2를 못가도록 visited표시하고,
path[1]에 2를 대입

그리곤 도달하면 역추적을 진행하는 코드인데..

시간초과가 났다..

시간초과가 날만한 곳은, 위의 구간이다.
코드의 비용상 구조의 문제 때문에 시간초과가 난 것은 아닌 것 같고,
무한루프가 걸리는 부분이 있다고 해석이 된다.

for문은 어짜피 N되면 빠져나오고,
while문에서 nextNode라는 큐가 안비워질 경우를 상정할 수 있을텐데..

?????????????

혹시 몇 %에서 멈추는지 보려고 똑같은 코드를 제출했는데
이번에는 맞았다고 뜬다..?!?

https://www.acmicpc.net/blog/view/55
언어마다 시간 보너스가 있다는데
감안하고도 틀렸던 답을..
그대로 다시 붙여넣었는데 왜 되는걸까??

흠...

풀이

우선 BFS대로 풀었지만,
BFS에선 최단거리만 찾아내지, 최단거리의 경로는 저장하지 않으므로,
path라는 배열을 하나 만들었고,
해당 인덱스가 각각 정점을 의미하며,
들어가는 값은 본인 이전의 정점을 넣도록 기록해 나갔다.

그렇게하면 BFS이후에 역추적을 할 수 있고,
역추적과 동시에 최단거리를 구한다.

추가

추가로 DFS에서 최단거리를 구하려면,
무조건 모든 경우의 수를 다 계산하고 거리를 구한 후에,
해당 값들 중 최소값을 찾으면 된다.

따라서 불필요하지만,
언젠가는 DFS를 사용하고 최단거리를 사용하는게 빠를 문제가 생길 수도 있다.

profile
Time Waits for No One

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN