Key Idea
- 지도에 있는 섬을 파악하기 위해 BFS를 사용해서 섬의 가장자리(값이 1이면서 상하좌우 중 하나라도 0) Point 들을 Island 객체 하나에 저장
- Island 객체들 간의 Point 를 비교하여 수직 수평에 있는 점들 사이의 거리를 구하여 2 이상인 것들을 추려내어
- Island 2개의 인덱스와 둘간의 거리를 저장한 Edge 객체를 생성하여 우선순위 큐에 삽입합니다
- 이후 union , find 를 이용하여 섬간 연결 거리의 최솟값을 구합니다
- 모든 섬을 연결하는 다리들이 최소거리 일 때, 이 다리들의 개수는
섬의 개수보다 하나 작은 값
이 됩니다- 따라서, 모든 섬을 연결하는 것이 불가능 한 경우는 다리의 개수가
섬의 개수 - 1
가 아닐 때가 됩니다
private static void BFS(int x, int y, ArrayList<Point> tempPoints){
Queue<Point> queue = new LinkedList<>();
Point point = new Point(x, y);
queue.add(point);
visited[point.x][point.y] = true;
while (!queue.isEmpty()){
Point current = queue.poll();
boolean check = false;
for(int i = 0; i < 4; i++){
int nx = current.x + dx[i];
int ny = current.y + dy[i];
if(nx >= 0 && ny >= 0 && nx < N && ny < M && !visited[nx][ny]){
if(map[nx][ny] == 1){
queue.add(new Point(nx, ny));
visited[nx][ny] = true;
}
else
check = true;
}
}
if(check)
tempPoints.add(current);
}
}
private static void bridge(){
for(int i = 0; i < islands.size() - 1; i++)
for (int j = i + 1; j < islands.size(); j++)
for(Point a : islands.get(i).points)
for(Point b : islands.get(j).points)
if(a.x == b.x || a.y == b.y){
int distance = Math.abs(a.x - b.x) + Math.abs(a.y - b. y) - 1;
if(distance >= 2 && !isIsland(a, b))
priorityQueue.add(new Edge(i, j, distance));
}
islands.size() - 1
가 아니라면 모든 섬을 연결할 수 없는 경우이므로 값을 -1로 바꿔줍니다 while(!priorityQueue.isEmpty()){
Edge current = priorityQueue.poll();
if(find(current.u) != find(current.v)){
union(current.u, current.v);
result += current.w;
cnt++;
}
}
if(cnt != islands.size() - 1)
result = -1;
import java.util.*;
class Point{
int x;
int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
}
class Island{
ArrayList<Point> points;
public Island(ArrayList<Point> points){
this.points = points;
}
}
class Edge implements Comparable<Edge>{
int u;
int v;
int w;
public Edge(int u, int v, int w){
this.u = u;
this.v = v;
this.w = w;
}
@Override
public int compareTo(Edge o) {
return w - o.w;
}
}
public class Main {
private static int N, M, result;
private static int[] dx = {0, 1, 0, -1};
private static int[] dy = {1, 0, -1, 0};
private static int[] parent;
private static int[][] map;
private static boolean[][] visited;
private static ArrayList<Island> islands = new ArrayList<>();
private static PriorityQueue<Edge> priorityQueue = new PriorityQueue<>();
public static void main(String[] args) {
int cnt = 0;
Scanner scanner = new Scanner(System.in);
N = scanner.nextInt();
M = scanner.nextInt();
map = new int[N][M];
visited = new boolean[N][M];
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
map[i][j] = scanner.nextInt();
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
if(map[i][j] == 1 && !visited[i][j]){
ArrayList<Point> tempPoints = new ArrayList<>();
BFS(i, j, tempPoints);
islands.add(new Island(tempPoints));
}
parent = new int[islands.size()];
for(int i = 0; i < islands.size(); i++)
parent[i] = i;
bridge();
while(!priorityQueue.isEmpty()){
Edge current = priorityQueue.poll();
if(find(current.u) != find(current.v)){
union(current.u, current.v);
result += current.w;
cnt++;
}
}
if(cnt != islands.size() - 1)
result = -1;
System.out.println(result);
scanner.close();
}
private static void BFS(int x, int y, ArrayList<Point> tempPoints){
Queue<Point> queue = new LinkedList<>();
Point point = new Point(x, y);
queue.add(point);
visited[point.x][point.y] = true;
while (!queue.isEmpty()){
Point current = queue.poll();
boolean check = false;
for(int i = 0; i < 4; i++){
int nx = current.x + dx[i];
int ny = current.y + dy[i];
if(nx >= 0 && ny >= 0 && nx < N && ny < M && !visited[nx][ny]){
if(map[nx][ny] == 1){
queue.add(new Point(nx, ny));
visited[nx][ny] = true;
}
else
check = true;
}
}
if(check)
tempPoints.add(current);
}
}
private static boolean isIsland(Point a, Point b){
int nx = a.x - b.x, ny = a.y - b.y;
if(nx == 0){ // same row
if(ny < 0){
for(int i = a.y + 1; i < b.y; i++)
if(map[a.x][i] == 1)
return true;
}
else{
for(int i = b.y + 1; i < a.y; i++)
if(map[a.x][i] == 1)
return true;
}
}
else{ // same col
if(nx < 0){
for(int i = a.x + 1; i < b.x; i++)
if(map[i][a.y] == 1)
return true;
}
else{
for(int i = b.x + 1; i < a.x; i++)
if(map[i][a.y] == 1)
return true;
}
}
return false;
}
private static void bridge(){
for(int i = 0; i < islands.size() - 1; i++)
for (int j = i + 1; j < islands.size(); j++)
for(Point a : islands.get(i).points)
for(Point b : islands.get(j).points)
if(a.x == b.x || a.y == b.y){
int distance = Math.abs(a.x - b.x) + Math.abs(a.y - b. y) - 1;
if(distance >= 2 && !isIsland(a, b))
priorityQueue.add(new Edge(i, j, distance));
}
}
private static int find(int n){
if(parent[n] == n)
return n;
return parent[n] = find(parent[n]);
}
private static void union(int a, int b){
int parent_a = find(a), parent_b = find(b);
if(parent_a < parent_b)
parent[parent_b] = parent_a;
else
parent[parent_a] = parent_b;
}
}