SWEA 1238 - 하나로
Updated:
Java
1238 번 - 하나로
문제
n개의 섬이 있으며, 각 섬을 이어 모든 섬을 오갈 수 있게 해야한다.
섬을 잇는 비용은 환경 부담 세율(E)과 각 해저터널 길이(L)의 제곱의 곱(E * L^2) 이다.
섬을 잇는 최소 비용은?
접근 방법
우선 섬과 섬을 잇는 모든 비용을 2차원 배열을 통해 구하였다.
이후 간선을 잇는 최소 비용을 구하는 문제이므로, Prim 알고리즘을 사용하여 해결하였다.
코드
import java.io.*;
import java.util.*;
class Solution {
static int n;
static double[][] island;
static double e, result;
static int[] x,y;
public static void main(String []args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk;
int tc = stoi(br.readLine());
for(int tidx = 1; tidx <= tc; tidx++) {
result = 0;
n = stoi(br.readLine());
island = new double[n][n];
x = new int[n];
y = new int[n];
stk = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++) {
x[i] = stoi(stk.nextToken());
}
stk = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++) {
y[i] = stoi(stk.nextToken());
}
e = Double.parseDouble(br.readLine());
// 섬을 잇는 모든 비용을 계산한다.
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(i == j)
continue;
island[i][j] = (Math.pow(x[i] - x[j], 2) + Math.pow(y[i] - y[j], 2)) * e;
}
}
// prim 알고리즘
boolean vis[] = new boolean[n];
double[] minEdge = new double[n];
Arrays.fill(minEdge, Double.MAX_VALUE); // 가장 최소의 간선을 찾아야 하므로, 초기 값은 Max
minEdge[0] = 0; // 첫 시작 점은 0으로 한다.
int minVertex = 0;
for(int c = 0; c < n; c++) {
double min = Double.MAX_VALUE;
for(int i = 0; i < n; i++) {
if(!vis[i] && min > minEdge[i]) { // 현재 저장 된 간선 중에 가장 값이 적은 간선을 선택한다. 처음은 0이 선택된다.
min = minEdge[i];
minVertex = i; // 그것과 연결 된 vertex
}
}
result += min;
vis[minVertex] = true;
for(int i = 0; i < n; i++) {
// 현재 vertex와 연결된 간선들과 이전 vertex와 연결 되었던 간선들의 값을 비교한다.
// 이전 vertex의 연결된 간선의 비용보다 현재 vertex에 연결하는 간선의 비용이 더 작다면 갱신한다.
if(!vis[i] && island[minVertex][i] != 0 && minEdge[i] > island[minVertex][i]) {
minEdge[i] = island[minVertex][i];
}
}
}
long result_l = Math.round(result);
System.out.println("#" + tidx + " " + result_l);
}
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
코드 - Priority Queue
import java.io.*;
import java.util.*;
class Solution {
static class Node implements Comparable<Node> {
int end; // 현재 정과 연결 되어 있는 끝 정점
double weight; // 가중치
public Node(int end, double weight) {
this.end = end;
this.weight = weight;
}
@Override
public int compareTo(Node o) {
return Double.compare(weight,o.weight);
}
}
static int n;
static List<List<Node>> island;
static double e, result;
static int[] x,y;
public static void main(String []args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk;
int tc = stoi(br.readLine());
for(int tidx = 1; tidx <= tc; tidx++) {
result = 0;
n = stoi(br.readLine());
island = new ArrayList<List<Node>>();
for(int i = 0; i < n; i++) {
island.add(new ArrayList<Node>());
}
x = new int[n];
y = new int[n];
stk = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++) {
x[i] = stoi(stk.nextToken());
}
stk = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++) {
y[i] = stoi(stk.nextToken());
}
e = Double.parseDouble(br.readLine());
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(i == j)
continue;
island.get(i).add(new Node(j, (Math.pow(x[i] - x[j], 2) + Math.pow(y[i] - y[j], 2)) * e));
}
}
// prim 알고리즘
boolean vis[] = new boolean[n];
double[] minEdge = new double[n];
Arrays.fill(minEdge, Double.MAX_VALUE);
int minVertex = 0;
minEdge[0] = 0;
PriorityQueue<Node> queue = new PriorityQueue<>();
queue.add(new Node(0,0));
while(!queue.isEmpty()) {
double min = Double.MAX_VALUE;
Node curNode = queue.poll();
int curN = curNode.end;
if(vis[curN]) continue;
vis[curN] = true;
result += curNode.weight;
for(Node list : island.get(curN)) {
if(minEdge[list.end] > list.weight) {
minEdge[list.end] = list.weight;
queue.add(new Node(list.end, minEdge[list.end]));
}
}
}
long result_l = Math.round(result);
System.out.println("#" + tidx + " " + result_l);
}
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
난이도
⭐⭐★★★
후기
prim, kruscal, dijkstra를 공부해야한다.
개선할 점
없