오늘의 알고리즘

[C++] 백준 17472 다리 만들기 2

하늘하늘 . 2023. 5. 19. 23:29
#include <iostream>  
#include <vector>
#include <algorithm>
#include <tuple>
#include <queue>
 
using namespace std;
 
int N, M, number;
int DirX[4] = { 1, -1, 0, 0 };
int DirY[4] = { 0, 0, 1, -1 };
 
int arr[11][11];
int check[11][11];
int visit[7];
int parent[7];
 
vector<tuple<int, int, int>> vec;
vector<int> graph[7];
 
bool cmp(tuple<int, int, int> dist1, tuple<int, int, int> dist2)
{
    if (get<2>(dist1) == get<2>(dist2))
    {
        if (get<0>(dist1) == get<0>(dist2))
            return get<1>(dist1) < get<1>(dist2);
 
        else
            return get<0>(dist1) < get<0>(dist2);
    }
 
    else
        return get<2>(dist1) < get<2>(dist2);
}
 
int FindParent(int x)
{
    if (parent[x] == x)
        return x;
 
    else
        return parent[x] = FindParent(parent[x]);
}
 
bool ParentCheck(int x, int y)
{
    x = FindParent(x);
    y = FindParent(y);
 
    if (x == y)
        return true;
 
    else
    {
        parent[y] = x;
 
        return false;
    }
}
 
void DFS(int x, int y)
{
    if (check[x][y])
        return;
 
    check[x][y] = true;
    arr[x][y] = number;
 
    for (int i = 0; i < 4; ++i)
    {
        int nextX = x + DirX[i];
        int nextY = y + DirY[i];
 
        if (nextX >= 0 && nextX < N &&
            nextY >= 0 && nextY <= M)
        {
            if (arr[nextX][nextY] && !check[nextX][nextY])
            {
                DFS(nextX, nextY);
            }
        }
    }
}
 
int main()
{
    cin >> N >> M;
 
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < M; ++j)
        {
            cin >> arr[i][j];
        }
    }
 
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < M; ++j)
        {
            if (arr[i][j])
            {
                if (!check[i][j])
                    ++number;
 
                DFS(i, j);
            }
        }
    }
 
    for (int i = 1; i <= number; ++i)
    {
        parent[i] = i;
    }
 
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < M; ++j)
        {
            if (arr[i][j])
            {
                for (int z = 0; z < 4; ++z)
                {
                    int x = i;
                    int y = j;
                    int dist = 0;
 
                    while (true)
                    {
                        x += DirX[z];
                        y += DirY[z];
 
                        if (x < 0 || x > N || y < 0 || y > M || arr[x][y] == arr[i][j])
                            break;
 
                        if (arr[x][y])
                        {
                            vec.push_back({ arr[i][j], arr[x][y], dist });
                            break;
                        }
 
                        ++dist;
                    }
                }
            }
        }
    }
 
    sort(vec.begin(), vec.end(), cmp);
 
    int ans = 0;
 
    for (int i = 0; i < vec.size(); ++i)
    {
        int x = get<0>(vec[i]);
        int y = get<1>(vec[i]);
        int dist = get<2>(vec[i]);
 
        if (dist < 2) 
            continue;
 
        if (!ParentCheck(x, y))
        {
            graph[x].push_back(y);
            graph[y].push_back(x);
 
            ans += dist;
        }
    }
 
    int count = 1;
    queue<int> que;
    que.push(1);
 
    while (!que.empty())
    {
        int now = que.front();
        que.pop();
        visit[now] = true;
 
        for (int i = 0; i < graph[now].size(); ++i)
        {
            int next = graph[now][i];
 
            if (!visit[next])
            {
                que.push(next);
                ++count;
            }
        }
    }
 
    if (count != number)
        cout << -1;
 
    else
        cout << ans;
 
    return 0;
}

부모를 찾아서 하나로 연결을 시켜야하는 알고리즘입니다.

선을 만드는 게 관건이었는데 한 개의 섬을 DFS로 모든 위치를 같은 번호로 바꿉니다.

그렇게 된다면 섬이 어디에 있는지 얼마나 거리가 차이나는지 확인 할 수 있습니다.

최대 크기가 크지 않기 때문에 모든 위치에서 모든 방향으로 확인을 해서 거리를 구합니다.

그 거리를 vec에 넣어서 가장 짧은 선으로 부모를 확인합니다.