17472번: 다리 만들기 2
첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 N개의 줄에 지도의 정보가 주어진다. 각 줄은 M개의 수로 이루어져 있으며, 수는 0 또는 1이다. 0은 바다, 1은 땅을 의미한다.
www.acmicpc.net
풀이
1. 섬들을 2번부터 시작해서 라벨링 한다!!
-> bfs 이용
2. 이제 각 섬에서 다른 섬까지 연결 가능한 모든 다리 생성 후 vector에 저장
-> 길이가 2 이상이여야됨!!
-> 두개의 섬 라벨과 다리 길이 value로 이루어진 struct로 관리
3. 길이 작은 순으로 sort 후 크루스칼
4. 모든 섬이 연결이 안됬으면 -1 출력
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
// 유니온파인드를 쓸거임
// 그 이전에 각 섬을 노드
// 연결가능한 모든 경우를 다 간선으로 만듬
int n, m;
int map[101][101];
int parent[10];
int d_r[4] = { 1,-1,0,0 };
int d_c[4] = { 0,0,1,-1 };
struct bridge {
int a, b;
int value;
};
bool cmp(bridge a, bridge b)
{
return a.value < b.value;
}
int getParent(int x)
{
if (parent[x] == x)
return x;
return parent[x] = getParent(parent[x]);
}
void connect(int x, int y)
{
x = getParent(x);
y = getParent(y);
if (x > y)
parent[x] = y;
else
parent[y] = x;
}
void bfs(int r, int c, int cnt)
{
map[r][c] = cnt;
queue<pair<int, int> > q;
q.push(make_pair(r, c));
while (!q.empty())
{
int now_r = q.front().first;
int now_c = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int new_r = now_r + d_r[i];
int new_c = now_c + d_c[i];
if (new_r < 0 || new_c < 0 || new_r >= n || new_c >= m)
continue;
if (map[new_r][new_c] == 1)
{
map[new_r][new_c] = cnt;
q.push(make_pair(new_r, new_c));
}
}
}
}
pair<int,int> try_bridge(int r, int c, int way)//첫번째는 길이, 두번째는 누구랑!
{
int cnt = 0;
while (true)
{
r += d_r[way];
c += d_c[way];
if (r < 0 || c < 0 || r >= n || c >= m)
return make_pair(-1,-1);
if (map[r][c] != 0)
return make_pair(cnt, map[r][c]);
cnt++;
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> map[i][j];
int cnt = 2;
for(int i=0;i<n;i++)
for (int j = 0; j < m; j++)
{
if (map[i][j] == 1)
{
bfs(i, j, cnt);
cnt++;
}
}
//섬은 2번부터 cnt-1까지 있음!!
//이제 가능한 모든 다리들 만들기!
vector<bridge> v;
for(int i=0;i<n;i++)
for (int j = 0; j < m; j++)
{
if (map[i][j] != 0)
{
for (int k = 0; k < 4; k++)
{
int new_r = i + d_r[k];
int new_c = j + d_c[k];
if (new_r < 0 || new_c < 0 || new_r >= n || new_c >= m)
continue;
if (map[new_r][new_c] == 0)//바다랑 겹쳐 있는 땅
{
if (try_bridge(i, j, k).first != -1)//-1이면 다리를 못짓는 다는 소리임
{
if (try_bridge(i, j, k).first >= 2)//다리 길이는 반드시 2 이상
{
bridge tmp;
tmp.a = map[i][j];
tmp.b = try_bridge(i, j, k).second;
tmp.value = try_bridge(i, j, k).first;
v.push_back(tmp);
}
}
}
}
}
}
sort(v.begin(), v.end(), cmp);
int answer = 0;
for (int i = 2; i < cnt; i++)
parent[i] = i;
for (int i = 0; i < v.size(); i++)
{
if (getParent(v[i].a) != getParent(v[i].b))
{
connect(v[i].a, v[i].b);
answer += v[i].value;
}
}
int final_parent = getParent(2);
for (int i = 3; i < cnt; i++)
{
if (getParent(i) != final_parent)
answer = -1;
}
cout << answer << endl;
return 0;
}
'c++ > Baekjoon Online' 카테고리의 다른 글
백준 1700 : 멀티탭 스케줄링 C++ (0) | 2021.06.24 |
---|---|
백준 2579 : 계단 오르기 C++ (0) | 2020.11.20 |
백준 : 기타줄 C++ (0) | 2020.11.18 |
백준 : 제곱수의 합 C++ (DP 연습!!) (0) | 2020.11.18 |
백준 : 퇴사 c++ (0) | 2020.11.18 |