<aside> 💛

시간 제한 : 1초, 난이도 : 골드1, 백준 : 17472번

</aside>

sumlist는 ArrayList<ArrayList<int[]>>타입으로, 여러 개의 섬을 각각 ArrayList<int[]> 형태로 저장하는 리스트이다.

각 섬(mlist)는 (행, 열) 좌표쌍을 담은 int[]로 이루어져 있고, sumlist는 이 섬들 mlist를 모아 놓은 리스트이다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;

public class Practice65 {
	static int[] dr = {-1, 0, 1, 0};
	static int[] dc = {0, 1, 0, -1};
	static int[] parent;
	static int[][]map;
	static int N, M;
	static int sNum;
	static boolean[][]visited;
	static ArrayList<ArrayList<int[]>> sumlist; //모든 섬 정보 저장
	static ArrayList<int[]> mlist; //하나의 섬 정보 저장
	static PriorityQueue<Edge> queue;
	
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		map = new int[N][M];
		visited = new boolean[N][M];
		for(int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j = 0; j < M; j++) {
				map[i][j] = Integer.parseInt(st.nextToken());
			}
		}
		
		sNum = 1;
		sumlist = new ArrayList<>();
		for(int i = 0; i < N; i++) {
			for(int j = 0; j < M; j++) {
				if(map[i][j] != 0 && visited[i][j] != true) {
					BFS(i, j);
					sNum++;
					sumlist.add(mlist);
				}
			}
		}
		queue = new PriorityQueue<>();
		
		for(int i = 0; i < sumlist.size(); i++) {
			ArrayList<int[]> now = sumlist.get(i);
			for(int j = 0; j < now.size(); j++) {
				int r = now.get(j)[0];
				int c = now.get(j)[1];
				int now_S = map[r][c];
				for(int d = 0; d < 4; d++) {
					int tempR = dr[d];
					int tempC = dc[d];
					int blenght = 0;
					while(r + tempR >= 0 && r + tempR < N && c + tempC >= 0 && c + tempC < M) {
						if(map[r + tempR][c + tempC] == now_S)
							break;
						else if(map[r + tempR][c + tempC] != 0) {
							if(blenght > 1)
								queue.add(new Edge(now_S, map[r + tempR][c + tempC], blenght));
							break;
						}else
							blenght++;
						if(tempR < 0)tempR--;
						else if(tempR > 0)tempR++;
						else if(tempC < 0)tempC--;
						else if(tempC > 0)tempC++;
						
					}
				}
			}
		}
		parent = new int[sNum];
		for(int i = 0; i < parent.length; i++) {
			parent[i] = i;
		}
		int useEdge = 0;
		int result = 0;
		while(!queue.isEmpty()) {
			Edge now = queue.poll();
			if(find(now.s) != find(now.e)) {
				union(now.s, now.e);
				result = result + now.v;
				useEdge++;
			}
		}
		if(useEdge == sNum - 2) {
			System.out.println(result);
		}else {
			System.out.println("-1");
		}
	}
	public static void union(int a, int b) {
		a = find(a);
		b = find(b);
		if(a != b) {
			parent[b] = a;
		}
	}
	public static int find(int a) {
		if(a == parent[a])
			return a;
		else
			return parent[a] = find(parent[a]);
	}
	
	private static void BFS(int i, int j) {
		Queue<int[]> queue = new LinkedList<>();
		mlist = new ArrayList<>();
		int[] start = {i, j};
		queue.add(start);
		mlist.add(start);
		visited[i][j] = true;
		map[i][j] = sNum;
		while(!queue.isEmpty()) {
			int now[] = queue.poll();
			int r = now[0];
			int c = now[1];
			for(int d = 0; d < 4; d++) {
				int tempR = dr[d];
				int tempC = dc[d];
				
				while(r + tempR >= 0 && r + tempR < N && c + tempC >= 0 && c + tempC < M) {
					if(visited[r + tempR][c + tempC] == false && map[r + tempR][c + tempC] != 0) {
						addNode(r + tempR, c + tempC, queue);
					}else break;
					if(tempR < 0)tempR--;
					else if(tempR > 0)tempR++;
					else if(tempC < 0)tempC--;
					else if(tempC > 0)tempC++;					
				}
			}
		}		
	}
	private static void addNode(int i, int j, Queue<int[]> queue) {
		map[i][j] = sNum;
		visited[i][j] = true;
		int[]temp = {i, j};
		mlist.add(temp);
		queue.add(temp);
	}
}

class Edge implements Comparable<Edge> {
	int s, e, v;
	
	Edge(int s, int e, int v){
		this.s = s;
		this.e = e;
		this.v = v;
	}
	@Override
	public int compareTo(Edge o) {
		return this.v - o.v;
	}	
}