February 07, 2022
백준 문제 링크 : https://www.acmicpc.net/problem/17472
import java.io.*;
import java.util.*;
public class Main {
static int N, M;
static int islandCnt;
static int[] island;
static int[][] board;
static int[] dy = {-1, 0, 1, 0};
static int[] dx = {0, 1, 0, -1};
public static void DFS(int r, int c) {
for(int i=0; i<4; i++) {
int rr = r + dy[i];
int cc = c + dx[i];
if(rr > N || rr < 1 || cc > M || cc < 1) continue;
if(board[rr][cc] == 1) {
board[rr][cc] = islandCnt;
DFS(rr,cc);
}
}
}
static class Road{
public int land1, land2, dis;
public Road(int land1, int land2, int dis) {
this.land1 = land1;
this.land2 = land2;
this.dis = dis;
}
}
public static boolean checkIsland() {
for(int i=2; i<=islandCnt; i++) {
if(island[i] != island[2] || island[2]==0) return false;
}
return true;
}
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
board = new int[N+1][M+1];
for(int i=1; i<=N; i++) {
st = new StringTokenizer(br.readLine());
for(int j=1; j<=M; j++) {
board[i][j] = Integer.parseInt(st.nextToken());
}
}
// 섬의 개수 및 섬의 종류 체크
islandCnt = 1;
for(int i=1; i<=N; i++) {
for(int j=1; j<=M; j++) {
if(board[i][j] == 1) {
islandCnt++;
board[i][j] = islandCnt;
DFS(i,j);
}
}
}
// priorityQueue로 섬 연결정보 저장
PriorityQueue<Road> pq = new PriorityQueue<>((r1, r2)-> r1.dis - r2.dis);
for(int i=1; i<=N; i++) {
for(int j=1; j<=M; j++) {
if(board[i][j] > 1) {
// 위
int k = 1;
while(i - k > 0) {
if(board[i-k][j] == 0) k++;
else if(board[i-k][j] == board[i][j]) break;
else {
if(k >= 3) {
pq.add(new Road(board[i][j], board[i-k][j], k-1));
}
break;
}
}
// 아래
k = 1;
while(i + k < N+1) {
if(board[i+k][j] == 0) k++;
else if(board[i+k][j] == board[i][j]) break;
else {
if(k >= 3) {
pq.add(new Road(board[i][j], board[i+k][j], k-1));
}
break;
}
}
// 오른
k = 1;
while(j + k < M+1) {
if(board[i][j+k] == 0) k++;
else if(board[i][j+k] == board[i][j]) break;
else {
if(k >= 3) {
pq.add(new Road(board[i][j], board[i][j+k], k-1));
}
break;
}
}
// 왼
k = 1;
while(j - k > 0) {
if(board[i][j-k] == 0) k++;
else if(board[i][j-k] == board[i][j]) break;
else {
if(k >= 3) {
pq.add(new Road(board[i][j], board[i][j-k], k-1));
}
break;
}
}
}
}
}
// priorityQueue로 확인
int answer = 0;
island = new int[islandCnt+1];
while(!pq.isEmpty()) {
Road road = pq.poll();
// 둘다 연결이 안되어있는 경우
if(island[road.land1] == 0 && island[road.land2] == 0) {
island[road.land1] = island[road.land2] = road.land1;
answer += road.dis;
}
// 섬1은 연결되어있지않고, 섬2만 연결되어있는경우
else if(island[road.land1] == 0 && island[road.land2] != 0) {
island[road.land1] = island[road.land2];
answer+= road.dis;
}
// 섬2은 연결되어있지않고, 섬1만 연결되어있는경우
else if(island[road.land1] != 0 && island[road.land2] == 0) {
island[road.land2] = island[road.land1];
answer+= road.dis;
}
// 두 연결되어있는 섬을 연결해야하는 경우
else if(island[road.land1] != island[road.land2]) {
int checkVal = island[road.land2];
for(int i=2; i<=islandCnt; i++) {
if(island[i] == checkVal) island[i] = island[road.land1];
}
answer += road.dis;
}
// 두 섬이 이미 연결되어 있는경우는 패스
if(checkIsland()) break;
}
if(!checkIsland()) System.out.println("-1");
else System.out.println(answer);
}
}