알고리즘문제풀이
[JAVA] SWEA 1251 하나로 [Kruskal]
Hindsight..
2020. 8. 19. 21:27
전체 코드
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
public class SWEA_1251_하나로 {
static int N, T;
static double E;
static int arr[], sel[];
static boolean v[];
static ArrayList<int[]> arrList;
static int parent[];
static PriorityQueue<Vector> pq;
static class Vector implements Comparable<Vector> { // 시작점과 끝점 그리고 비용을 담는 클래스
int start, end;
long weight;
Vector(int start, int end, long weight) {
this.start = start;
this.end = end;
this.weight = weight;
}
@Override
public int compareTo(Vector o) {
if (this.weight > o.weight)
return 1;
else if (this.weight < o.weight)
return -1;
else
return 0;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
T = sc.nextInt();
int x[], y[];
long result, MIN;
for (int test = 1; test <= T; test++) {
arrList = new ArrayList<>();
N = sc.nextInt();
x = new int[N];
y = new int[N];
for (int i = 0; i < N; i++)
x[i] = sc.nextInt();
for (int i = 0; i < N; i++)
y[i] = sc.nextInt();
E = sc.nextDouble(); // 환경 세율
// makeCombination();
print();
makeSet();
MIN = Long.MAX_VALUE;
// for (int[] arr : arrList) {
pq = new PriorityQueue<Vector>();
getVectors(x, y); // 모든 연결점에 대해 두 점간의 환경비용을 계산해 연결한다.
result = 0;
for (int i = 0; i < N - 1; i++) { // 크루스칼을 통해 최소 비용 트리를 구한다.
Vector tmp = pq.poll();
int a = find(tmp.start); // 시작점의 정점을 찾는다
int b = find(tmp.end); // 끝점의 정점을 찾는다.
if (a == b) //만약 두 점의 정점이 같다면 다음 루프로
continue;
union(a, b); // 그렇지 않다면 두점을 연결한다.
result += tmp.weight; // 결과 값에 weight을 누적시킨다.
}
if (MIN > result)
MIN = result;
// }
System.out.println("#" + test + " " + MIN);
}
}
public static void print() {
for (int i = 0; i < arrList.size(); i++) {
System.out.println(Arrays.toString(arrList.get(i)));
}
}
public static void getVectors(int[] x, int[] y) { // 두 점 사이의 비용을 구해 vector ArrayList를 생성
for (int i = 0; i < N - 1; i++) {
long weight = (long) (E * (Math.pow((x[i] - x[i + 1]), 2) + Math.pow((y[i] - y[i + 1]), 2)));
pq.add(new Vector(i, i + 1, weight));
}
long weight = (long) (E * (Math.pow((x[0] - x[N - 1]), 2) + Math.pow((y[0] - y[N - 1]), 2)));
pq.add(new Vector(N - 1, 0, weight));
}
public static void makeSet() { // 정점 배열을 생성
parent = new int[N + 1];
for (int i = 0; i < N + 1; i++) {
parent[i] = i;
}
}
public static int find(int a) { // 점에 대해 정점을 찾는 함수
if (a == parent[a])
return a;
parent[a] = find(parent[a]);
return parent[a];
}
public static void union(int a, int b) { // 두점의 정점을 찾아 합치는 함수
int aRoot = find(a);
int bRoot = find(b);
if (aRoot != bRoot) {
parent[aRoot] = b;
} else {
return;
}
}
}
전형적인 최소비용트리문제이고, 크루스칼을 이용하면 쉽게 풀 수 있었다.
각 점들간 환경 비용을 계산하고, 그 점들을 모두 이을 수 있는 최소 비용을 찾는 문제이다.
크루스칼에 대해서는 자료가 굉장히 많아 설명을 생략한다.