Prim: 정점을 점점 확장해 나가는 방식 (힙을 써서 구현 - 정점번호, 가중치 저장) --> 최소값을 우선 순위 큐를 이용하면 최소 값을 logE만에 찾을 수 있다. 이 경우 시간복잡도는 O(ElogE)가 된다. 모든 간선이 힙에 한번 씩 들어갔다가 나오기 때문
그래프에서 아무 정점이나 선택한다.
선택한 정점과 선택하지 않은 정점을 연결하는 간선 중에 최소값을 고른다. 이 간선을 (u, v)라고 한다.
선택한 간선을 최소 스패닝 트리에 추가하고, 선택하지 않았던 정점 v를 선택한다.
2번으로 돌아간다
Kruskal: 간선을 점점 확장해 나가는 방법
가중치가 작은 edge부터 살펴본다 --> 간선의 길이 순으로 먼저 정렬해야 한다. O(ElogE)
edge e가 (u, v, c)일 때, u와 v가 서로 다른 집합이면 e를 최소 스패닝 트리에 추가한다. O(E) - union/find 연산
Prim 알고리즘 풀이
import java.util.*;
publicclassMain{
publicstaticvoidmain(String[] args){
Scanner in = new Scanner(System.in);
int v = in.nextInt();
int e = in.nextInt();
LinkedList<Edge>[] pair = new LinkedList[v + 1];
HashSet<Integer> vSet = new HashSet<Integer>();
for (int i = 1; i <= v; i++) {
pair[i] = new LinkedList<Edge>();
vSet.add(i);
}
for (int i = 0; i < e; i++) {
int start = in.nextInt();
int end = in.nextInt();
long cost = in.nextLong();
pair[start].add(new Edge(end, cost));
pair[end].add(new Edge(start, cost));
}
int currentNode = 1;
long ans = 0;
vSet.remove(1);
PriorityQueue<Edge> pq = new PriorityQueue<Edge>();
pq.addAll(pair[currentNode]);
while (!vSet.isEmpty()) {
Edge minEdge = pq.poll();
if (vSet.contains(minEdge.v)) {
ans += minEdge.cost;
currentNode = minEdge.v;
vSet.remove(currentNode);
pq.addAll(pair[currentNode]);
}
}
System.out.println(ans);
}
}
classEdgeimplementsComparable<Edge> {
int v;
long cost;
publicEdge(int v, long cost){
this.v = v;
this.cost = cost;
}
@OverridepublicintcompareTo(Edge o){
return Long.compare(this.cost, o.cost);
}
}
Kruskal 알고리즘 풀이
import java.util.*;
publicclassMain{
publicstaticvoidmain(String[] args){
Scanner in = new Scanner(System.in);
int v = in.nextInt();
int e = in.nextInt();
PriorityQueue<Edge> pq = new PriorityQueue<Edge>();
int vSet[] = newint[v + 1];
for (int i = 1; i <= v; i++) {
vSet[i] = i;
}
for (int i = 0; i < e; i++) {
int start = in.nextInt();
int end = in.nextInt();
long cost = in.nextLong();
pq.add(new Edge(start, end, cost));
}
long ans = 0;
if (!pq.isEmpty()) {
Edge firstEdge = pq.poll();
ans += firstEdge.cost;
union(firstEdge.v1, firstEdge.v2, vSet);
}
while (!isFinished(vSet) && !pq.isEmpty()) {
Edge minEdge = pq.poll();
int v1Contains = find(minEdge.v1, vSet);
int v2Contains = find(minEdge.v2, vSet);
if (v1Contains != v2Contains) {
ans += minEdge.cost;
union(minEdge.v1, minEdge.v2, vSet);
}
}
System.out.println(ans);
}
publicstaticvoidunion(int x, int y, int[] vSet){
int ux = find(x, vSet);
int uy = find(y, vSet);
vSet[uy] = ux;
}
publicstaticintfind(int x, int[] vSet){
if (vSet[x] == x) {
return x;
}
vSet[x] = find(vSet[x], vSet);
return vSet[x];
}
publicstaticbooleanisFinished(int[] vSet){
int now = vSet[1];
for (int i = 1; i < vSet.length; i++) {
if (vSet[i] != now) {
returnfalse;
}
}
returntrue;
}
}
classEdgeimplementsComparable<Edge> {
int v1, v2;
long cost;
publicEdge(int v1, int v2, long cost){
this.v1 = v1;
this.v2 = v2;
this.cost = cost;
}
@OverridepublicintcompareTo(Edge o){
return Long.compare(this.cost, o.cost);
}
}
여기서는 괜찮았지만, 원래 viewpager2의 layout_width와 layout_height는 match_parent로 해 주어야 에러가 안난다고 한다. 그래서 만약에 크기를 지정해서 사용하고 싶다면 viewpager2를 다른 뷰 그룹으로 감싸주고 상위 뷰의 크기를 변경하도록 해야한다.
ScreenSlidePagerAdapter는 알아서 TutorialFragment를 객체를 만든다. 이 때 주의할 점은 button객체와 onclick을 붙일 때 fragment 안에 있는 것이므로 fragment에서 해야하지 뒤에 나오는 TutorialActivity에서 하면 Null Pointer Error가 나와서 안됨
참고로 안드로이드 프로젝트는 MVP 패턴(Model-View-Presenter)으로 패키지를 나누는게 좋다고 한다.
MVP 패턴
View: Activity/Fragment가 해당되며 실제 뷰에 대한 직접적인 접근을 담당한다. 뷰에서 발생하는 이벤트는 직접 핸들링 할 수 있으나 Presenter에 위임하도록 한다. 위임하는 방법은 액티비티가 뷰 인터페이스를 구현해서 Presenter에서 코드를 만들 인터페이스를 갖도록 하면 된다고 한다. 이렇게 하면 특정 뷰와 결합되지 않고 가상 뷰를 구현하여 간단한 유닛 테스트를 할 수 있다.
Presenter: MVC 모델에서 컨트롤러 역할과 비슷한데, 뷰에 연결되는 것이 아니라 인터페이스로 연결된다. 뷰와 모델 사이의 자료 전달 역할을 한다.
Model: 앱 데이터를 말하는데, 데이터 그 자체 외에도 데이터를 관리, 수집, 수정 등을 하는 부분이다.