오늘의 알고리즘
[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에 넣어서 가장 짧은 선으로 부모를 확인합니다.