[문제][알고스팟] 근거리네트워크 (LAN) (1)
2018. 6. 6. 18:10ㆍ[개발] 지식/알고리즘 문제풀이
오늘 컨디션이 안좋아서 어려운 문제는 아니었는데 너무 풀기싫었고 힘들었다.
오랜 기간 생각이 너무 많아서 오히려 잡념이 파고들 수 있는 휴일에 컨디션이 더 안좋다.
그래도 지금까지처럼 짓눌려버리면 시간만 낭비할까봐 굳이 문제를 풀려고 했다.
이 문제는 알고스팟 최소스패닝 대표문제(예제)? 이다.
크루스칼, 프림 알고리즘 둘 다 사용해도 풀린다고 한다.
그런데 책 자체가 C기준이라 그런지 Java로 풀었을때 시간초과가 났다.
3개의 댓글이 있습니다.
이런 댓글들이 보이는걸로 봐선, 나만의 문제는 아닌것 같다.
일단 크루스칼로 풀이한 소스를 올리고 곧 프림 + 최적화 소스를 올릴 예정이다.
풀이 코드 (+크루스칼)
package apss;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;
public class Lan {
public static int N,M,E;
public static int node[][];
public static int Set[];
public static double Edge[][];
public static double sum;
public static int selected;
public static void main(String[] args) throws Exception{
System.setIn(new FileInputStream("D:\\sample_input.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine().trim());
for(int tc=1; tc<=T; tc++) {
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
E = N * N;
node = new int[N][2];
Set = new int[N]; // start with 1. index 0 is not used.
Edge = new double[E][3];
sum = 0;
selected = 0;
// x좌표
st = new StringTokenizer(br.readLine());
for(int i=0; i<N; i++) {
node[i][0] = Integer.parseInt(st.nextToken());
}
// y좌표
st = new StringTokenizer(br.readLine());
for(int i=0; i<N; i++) {
node[i][1] = Integer.parseInt(st.nextToken());
}
Arrays.fill(Set, -1);
// join
for(int i=0; i<M; i++) {
st = new StringTokenizer(br.readLine());
int s = Integer.parseInt(st.nextToken());
int e = Integer.parseInt(st.nextToken());
join(s,e);
selected++;
}
for(int i=0; i<E; i++) {
Edge[i][0] = i/N;
Edge[i][1] = i%N;
Edge[i][2] = Math.sqrt(
Math.abs(node[(int)Edge[i][0]][0] - node[(int)Edge[i][1]][0]) * Math.abs(node[(int)Edge[i][0]][0] - node[(int)Edge[i][1]][0]) +
Math.abs(node[(int)Edge[i][0]][1] - node[(int)Edge[i][1]][1]) * Math.abs(node[(int)Edge[i][0]][1] - node[(int)Edge[i][1]][1])
);
}
Arrays.sort(Edge, new Comparator<double[]>() {
@Override
public int compare(double[] o1, double[] o2) {
// TODO Auto-generated method stub
return o1[2] - o2[2] > 0 ? 1 : -1;
}
});
for(int i=0; i<E; i++) {
if(group((int)Edge[i][0]) != group((int)Edge[i][1])) {
sum += Edge[i][2];
selected++;
join((int)Edge[i][0], (int)Edge[i][1]);
}
}
bw.flush();
bw.write(sum+"\n");
}
bw.close();
}
// Union-Find : group
public static int group(int n) {
if (Set[n] == -1) return n;
return Set[n] = group(Set[n]); // path compression
}
// Union-Find : join
public static void join(int a, int b) {
int A = group(a), B = group(b);
if (A != B) Set[A] = B;
}
}
생각해볼점
1. 사소한 테크닉이 부족한것 같다. 예를들어 Comparator 을 사용한 다중 배열의 정렬기준을 정의하는데, 아직도 혼동이 있다. 그리고 좀 더 차분히 생각하면 더 효율적인 자료구조를 활용할 수 있을텐데 마음이 급하다보니 직관적인 방법을 끝까지 밀고 나가려는 습관이 있다.
2. 하나의 알고리즘을 공부할때는 완벽하게 이해해야 응용을 할 수 있다. 진도를 나가는게 목적이 아니라 느리더라도 완벽하게 이해해야 응용이 가능하다.
'[개발] 지식 > 알고리즘 문제풀이' 카테고리의 다른 글
[문제][알고스팟] BOARDCOVER (게임판 덮기) (0) | 2018.08.22 |
---|---|
[문제][알고스팟] PICNIC (0) | 2018.08.13 |
[문제][알고스팟] EDITORWARS (에디터 전쟁) (0) | 2018.05.27 |
[문제][Algospot] PROMISES(선거공약) (0) | 2018.04.22 |
[문제] 감시 카메라 설치 (GALLERY) (0) | 2017.11.11 |
<