/* 문제설명 */

도현이는 컴퓨터와 컴퓨터를 모두 연결하는 네트워크를 구축하려 한다. 하지만 아쉽게도 허브가 있지 않아 컴퓨터와 컴퓨터를 직접 연결하여야 한다. 그런데 모두가 자료를 공유하기 위해서는 모든 컴퓨터가 연결이 되어 있어야 한다. (a와 b가 연결이 되어 있다는 말은 a에서 b로의 경로가 존재한다는 것을 의미한다. a에서 b를 연결하는 선이 있고, b와 c를 연결하는 선이 있으면 a와 c는 연결이 되어 있다.)

그런데 이왕이면 컴퓨터를 연결하는 비용을 최소로 하여야 컴퓨터를 연결하는 비용 외에 다른 곳에 돈을 더 쓸 수 있을 것이다. 이제 각 컴퓨터를 연결하는데 필요한 비용이 주어졌을 때 모든 컴퓨터를 연결하는데 필요한 최소비용을 출력하라. 모든 컴퓨터를 연결할 수 없는 경우는 없다.

입력

첫째 줄에 컴퓨터의 수 N (1 ≤ N ≤ 1000)가 주어진다.

둘째 줄에는 연결할 수 있는 선의 수 M (1 ≤ M ≤ 100,000)가 주어진다.

셋째 줄부터 M+2번째 줄까지 총 M개의 줄에 각 컴퓨터를 연결하는데 드는 비용이 주어진다. 이 비용의 정보는 세 개의 정수로 주어지는데, 만약에 a b c 가 주어져 있다고 하면 a컴퓨터와 b컴퓨터를 연결하는데 비용이 c (1 ≤ c ≤ 10,000) 만큼 든다는 것을 의미한다. a와 b는 같을 수도 있다.

출력

모든 컴퓨터를 연결하는데 필요한 최소비용을 첫째 줄에 출력한다.

 

 

 

 


 

 

 

/* 풀이방법 */

 

https://jinniepark.tistory.com/55

 

[알고리즘 기본]Kruskal 알고리즘

Kruskal 알고리즘 MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다. 오늘은 크루스칼 알고리즘에 대해 더 자세히 살펴보도록 하겠다. 크루스칼 알고리즘은

jinniepark.tistory.com

 

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;

//네트워크 연결
public class b1922 {
	static int[] parent;
	static int find(int x) {
		if(x==parent[x])
			return x;
		else {
			parent[x]=find(parent[x]);
			return parent[x];
		}
	}
	static void union(int x,int y) {
		x = find(x);
		y = find(y);
		if(x!=y) {
			parent[y]=x;
		}
	}
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		int N = Integer.parseInt(br.readLine());	//노드의 수
		int M = Integer.parseInt(br.readLine());	//간선의 수
		parent = new int[N+1];
		for(int i=1;i<N+1;i++) {
			parent[i] = i;
		}
		
		ArrayList<Edgee> edges = new ArrayList<Edgee>();
		for(int i=1;i<M+1;i++) {
			st = new StringTokenizer(br.readLine());
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			int c = Integer.parseInt(st.nextToken());
			edges.add(new Edgee(a,b,c));
		}
		
		Collections.sort(edges);
		int total = 0;
		while(!edges.isEmpty()) {
			Edgee e = edges.remove(0);
			if(find(e.a)==find(e.b)) continue;
			total += e.weight;
			union(e.a,e.b);
		}
		System.out.println(total);
	}
}

class Edgee implements Comparable<Edgee>{
	int a;
	int b;
	int weight;
	
	public Edgee(int a, int b, int weight) {
		super();
		this.a = a;
		this.b = b;
		this.weight = weight;
	}

	@Override
	public int compareTo(Edgee o) {
		return Integer.compare(this.weight, o.weight);
	}
}

 

 

 

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][4485]녹색 옷 입은 애가 젤다지?  (1) 2021.09.27
[백준][11404]플로이드  (0) 2021.09.26
[백준][12865]평범한 베낭  (0) 2021.09.07
[백준][16236]아기상어  (0) 2021.08.25
[백준][1197]최소 스패닝 트리  (0) 2021.08.24

Kruskal 알고리즘 

MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다.

오늘은 크루스칼 알고리즘에 대해 더 자세히 살펴보도록 하겠다.

 

크루스칼 알고리즘은 일단 모든 간선을 오름차순으로 정렬하고

순서대로 이어나가다가 사이클이 발생하면 해당 간선은 건너뛴다. 참으로 간단하다.

 

크루스칼은 프림에 비해 희소 그래프인 경우, 그러니까 간선이 적은 경우 적합하고,

프림은 크루스칼에 비해 간선이 많이 존재하는 밀집그래프에 더 적합하다.

 

프림 알고리즘은 아래에서 더 자세하게 다룬다.

https://jinniepark.tistory.com/46

 

[알고리즘 기본]PRIM 알고리즘

PRIM 알고리즘 MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다. 오늘은 프림 알고리즘에 대해 더 자세히 살펴보도록 하겠다. 프림 알고리즘을 시작점을 중

jinniepark.tistory.com

 

일단을 개념적으로 구하는 방법을 그려보았다.


 

 

이때 사이클을 검사하는 알고리즘은 Union-Find 알고리즘이 쓰인다.


관련문제

https://www.acmicpc.net/problem/1922

 

1922번: 네트워크 연결

이 경우에 1-3, 2-3, 3-4, 4-5, 4-6을 연결하면 주어진 output이 나오게 된다.

www.acmicpc.net

https://jinniepark.tistory.com/56?category=952224

 

[백준][1922]네트워크 연결

/* 문제설명 */ 도현이는 컴퓨터와 컴퓨터를 모두 연결하는 네트워크를 구축하려 한다. 하지만 아쉽게도 허브가 있지 않아 컴퓨터와 컴퓨터를 직접 연결하여야 한다. 그런데 모두가 자료를 공유

jinniepark.tistory.com

 

/* 문제설명 */

이 문제는 아주 평범한 배낭에 관한 문제이다.

한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.

준서가 여행에 필요하다고 생각하는 N개의 물건이 있다. 각 물건은 무게 W와 가치 V를 가지는데, 해당 물건을 배낭에 넣어서 가면 준서가 V만큼 즐길 수 있다. 아직 행군을 해본 적이 없는 준서는 최대 K만큼의 무게만을 넣을 수 있는 배낭만 들고 다닐 수 있다. 준서가 최대한 즐거운 여행을 하기 위해 배낭에 넣을 수 있는 물건들의 가치의 최댓값을 알려주자.

입력

첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)가 주어진다.

입력으로 주어지는 모든 수는 정수이다.

출력

한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.

 

 

 

 


 

 

 

/* 풀이방법 */

이문제는 아~주 유명한 Knapsack algorithm을 사용해서 풀어야 한다.

베낭 알고리즘은 두가지 종류가 있는데,

물품을 쪼갤수 있는 Fraction Knapsack problem과 물건을 쪼갤 수 없는 0/1 Knapsack problem으로 나뉜다.

Fraction Knapsack problem는 그리드 알고리즘을 활용해야 하며, 0/1 Knapsack problem는 DP로 풀어야한다.

위의 문제는 물건을 쪼갤 수 없으므로 DP로 풀어야 한다..

 

자 그럼 최대 이윤을 배열에 저장해 가면서 풀어보자.

일단 최대 이윤을 저장하기 위해 아래와 같은 표를 만들었다.

여기서 아이템들은 백준문제의 예시를 그대로 사용했다.

아이템1은 무게 6, 가치 13 

아이템2는 무게 4, 가치 8

아이템3은 무게 3, 가치 6

아이템4는 무게 5, 가치 12를 지닌다.

 

 

 

 

 

이제 값을 저장해보자..

나는 나중에 코드 짤때, 범위인지 아닌지 알아내는거 쓰기 귀찮아서 위에 0번째 줄을 제로패딩 해줬다.

아이템1은 무게 6, 가치 13를 지닌다는 점을 생각하면서 채우자

 

 

 

 

 

 

 

일단 여기까지는 무난하게 진행된다. 이제 무게가 6kg면 아이템1은 담는게 가능하므로 저칸에 최고 가치인 13을 쓰게 된다.

 

 

 

 

 

 

자 그리고 옆칸도 무게 7에 아이템1만 있을 경우의 최고 가치이므로 당연히 13이 될 것이다.

 

 

 

 

 

 

 

이런식으로 다음줄도 채워보겠다. 아이템2는 무게 4, 가치 8을 지닌다.

 

 

 

 

 

 

 

사실 이때부터 비교해 주어야 할칸이 총 세칸이다.

일단 (2,5)에 위치한 초록색 칸이 의미하는 바에 대해 다시 생각해 봐야한다.

무게 제한이 5kg일때, 아이템 1,2만 가지고 가질수있는 최대 가치를 표현해야한다.

그러면 저 값을 위해 비교해야할 값은

첫째, 바로전 (2,4)에 위치한 연두색 칸이다. 해당 칸이 의미하는 바는 4kg제한에서 아이템 1,2만으로 가질수 있는 최대 가치이다. 1kg 늘어났다고해서 달라지는 바가 없을 수도 있지 않은가?

둘째, 바로위 (1,5)에 위치한 연두색 칸이다. 해당 칸이 의미하는 바는 5kg제한에서 아이템 1만으로 가질수 있는 최대 가치이다. 물건 하나 늘어났다고 해서 달라지는 바가 없을 수도 있지 않은가?

셋째는... 현재 아이템 무게를 뺀 가방에서 가질 수 있는 최고 가치현재 아이템의 가치를 더한 값이다.

해당 칸에서는 아이템2의 무게는 4이고 이번 문제에서 넣었던 물건은 또 넣을 수 없으므로, 

(1,1)에 위치한 주황색 칸에 있는 값이 최고 가치가 되는 것이다. 

이중 가장 큰값은 8 이므로 (2,5)에는 8을 입력하게 된다. 

 

사실 위와 같은 방법으로 계속 채워주면 된다.

 

 

 

 

 

 

 

 

 

자 채우고 채워서 여기까지 왔다.

사실 여기도 아까와 같은 방법으로 하면되는데, 다시한번 보겠다.

연두색 칸들이랑, 주황색칸 + 현재가치 중 가장 큰값을 택하면 된다.

지금 아이템3에 위치하고 있으므로 현재가치는 6. 따라서 6+8=14가 된다.

그럼 초록색 칸에는 가장 큰값인 14를 입력하게 된다.

 

 

다음줄도 마저 입력해보면..

 

 

 

 

 

 

이런 모양이 되고, 해당 예시에서 원하는 아이템 1,2,3,4를 가지고 7키로 제한의 가장 큰 가치는 (4,7)에 위치한 14가 되는것이다.

 

 

조만간 dp에 대해서도 한번 정리해야겠다는걸 많이 느꼈다..

 

 

 

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

//평범한 베낭
public class b12865 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		int N = Integer.parseInt(st.nextToken());
		int K = Integer.parseInt(st.nextToken());
		int[] w = new int[N+1];
		int[] v = new int[N+1];
		int[][] memo =new int[N+1][K+1];
		for(int i=1;i<=N;i++) {
			st = new StringTokenizer(br.readLine());
			w[i] = Integer.parseInt(st.nextToken());
			v[i] = Integer.parseInt(st.nextToken());
		}

		for(int i=1;i<=N;i++) {
			for(int j=1;j<=K;j++) {
				int pw = w[i];
				int pv = v[i];
				if(pw > j){
					memo[i][j] = memo[i-1][j];
	            }
	  			else{
	  				memo[i][j] = Math.max(memo[i-1][j], pv+memo[i-1][j-pw]);
	            }
			}
		}
		System.out.println(memo[N][K]);	
	}
}

 

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][11404]플로이드  (0) 2021.09.26
[백준][1922]네트워크 연결  (0) 2021.09.17
[백준][16236]아기상어  (0) 2021.08.25
[백준][1197]최소 스패닝 트리  (0) 2021.08.24
[백준][1987]알파벳  (1) 2021.08.19

 

성능 데이터 모델링의 개요

 

성능 데이터모델링이란?

데이터베이스 성능 향상을 목적으로 설계단계의 데이터 모델링 때부터 성능과 관련된 사항이 데이터 모델링에 반영될 수 있도록 하는 것

 

 

 

성능 데이터모델링 수행 절차

1. 데이터모델링을 할 때 정규화를 정확하게 수행한다.

 

2. 데이터베이스 용량산정을 수행한다.

    용량산정은 전체적인 데이터베이스에 발생되는 트랜잭션의 유형과 양을 분석하는 자료가 된다.

 

3. 데이터베이스에 발생되는 트랜잭션의 유형을 파악한다.

 

4. 용량과 트랜잭션의 유형에 따라 역정규화를 수행한다.

 

5. 이력모델의 조정, PK/FK 조정, 슈퍼타입/서브타입 조정 등을 수행한다.

 

6. 성능 관점에서 데이터 모델을 검증한다.

 

 

 


정규화

정규화 단계와 조건

  • 제1정규화 - 테이블의 컬럼이 원자값을 가지도록 테이블을 분해
  • 제2정규화 - 완전 함수 종속을 만족하도록 테이블을 분해
  • 제3정규화 - 이행적 함수 종속을 없애도록 테이블을 분해
  • BCNF(강화된 제 3정규화) - 모든 결정자가 후보키가 되도록 테이블을 분해

 

 


반정규화

테이블 반정규화 분류 반정규화 기법 내용
테이블 병합 1:1 관계 테이블 병합 1:1 관계를 통합해서 성능 향상
1:M 관계 테이블 병합 1:M 관계를 통합해서 성능 향상
슈퍼/서브타입 테이블 병합 슈퍼/서브 관계를 통합해서 성능 향상
테이블 분할 수직분할 칼럼단위의 테이블을 디스크 I/O를 분산처리 하기 위해 테이블을 1:1로 분리하여 성능향상
-> 트랜잭션의 처리되는 유형 파악을 먼저 해야함
수평분할 로우 단위로 집중 발생되는 트랜잭션을 분석해서 성능 향상을 위해 로우 단위로 데이터를 쪼갬
-> 관계음슴
테이블 추가 중복테이블 추가 다른 업무거나 서버가 다른 경우, 동일한 테이블 구조를 중복해서 원격 조인 같은거를 안하도록 함
통계테이블 추가 SUM, AVG같은걸 미리 계산해둠으로써 조회 성능 향상
이력테이블 추가 이력테이블 중에서 마스터 테이블에 존재하는 레코드를 중복해서 이력 테이블에 존재하는 방법은 반정규화의 유형
부분테이블 추가 하나의 테이블의 전체 칼럼 중 자주 이용하는 집중화된 칼럼이 있을 때, 이러한 칼럼들을 모아놓은 별도의 부분테이블을 추가하는 유형
칼럼의 반정규화 기법 내용
중복칼럼 추가 조인에 의해 처리할때, 조인을 감소시키기 위해 중복된 칼럼을 위치시킴
파생칼럼 추가 트랜잭션이 처리되는 시점에 계산에 의해 발성되는 성능 저하를 예방하기 위해 미리 값을 계산해서 칼럼에 보관
이력테이블 칼럼 추가 대량의 이력데이터를 처리할 때 불특정 날 조회나 최근 값을 조회 할 때 나타날 수 있는 성능 저하를 예방하기 위해 이력 테이블에 기능성 칼럼을 추가
PK에 의한 칼럼 추가 복합의미를 가지는 PK를 단일 속성으로 구성할 경우 발생됨. 단일 PK안에서 특정값을 별도로 조회하는 경우 성능 저하가 발생할 수 있으므로 일반속성으로 포함하는 방법임
응용시스템 오작동을 위한 칼럼 추가 업무적으로는 의미가 없으나 사용자가 데이터 처리를 하다가 잘못 처리하여 원래 값으로 복구하기를 원하는 경우 이전 데이터를 임시적으로 중복해서 보관하는 기법

 

반정규화 말고 다르게 처리하는 방법?

  • 뷰를 사용 >> 조인이 많이 해야하는 경우 
  • 클러스터링 적용, 인덱스 조정 >> 대량의 데이터 처리나 부분처리
  • 파티셔닝 기법 >> 대량의 데이터를 PK의 성격에 따라 부분적인 테이블로 분리
  • 응용 애플리케이션에서 구사하는 로직 변경

표준조인(Standard Join)

1) INNER JOIN

동일한 값이 있는 행만 반환된다. 

반드시 USING이나 ON조건절을 동반한다.

SELECT  A.ID A.NAME B.ID B.DATE
FROM STUDENT A INNER JOIN REGISTER B
ON A.ID=B.ID;

2) NATURAL JOIN

SQL Server은 지원하지 않는 기능이며 where절에서 JOIN조건은 정의 할 수 없다.

일치되는 모든 컬럼들에 대해서 JOIN이 이루어진다.

별명사용이 불가하다고 한다.

SELECT ID NAME DATE
FROM STUDENT NATURAL JOIN REGISTER;

 

3) USING 조건절

이친구도 별명사용이 불가하다고 한다.

동일한 이름을 가진 컬럼중 원하는 컬럼을 선택해서 조인할 수 있다. SQL Server은 지원하지 않는다.

SELECT ID NAME DATE
FROM STUDENT JOIN REGISTER
USING (ID);

 

4) ON 조건절

이친구는 별명 쓰는게 가능하다. 이친구는 USING과 다르게 컬럼명이 달라도 조인을 사용할 수 있지만 정확하게 어느 테이블의 컬럼인지 지정해주어야한다.

SELECT  A.ID A.NAME B.ID B.DATE
FROM STUDENT A JOIN REGISTER B
ON (A.ID=B.ID);

 

(+)

ON 조건절은 WHERE절과 충돌 없이 사용 가능하다

SELECT  A.ID A.NAME B.ID B.DATE
FROM STUDENT A JOIN REGISTER B
ON (A.ID=B.ID)
WHERE B.DATE = '20210831';

WHERE과 큰 차이점은 WHERE은 해당 절을 추출하지만, ON 조건절은 해당 부분만 JOIN하고 나머지 부분도 존재한다는 것이다.

 

5) 다중 테이블 JOIN

SELECT  A.ID A.NAME B.ID B.DATE
FROM STUDENT A JOIN REGISTER B
ON A.ID=B.ID
JOIN PROFESSOR C
ON B.PROFESSOR_ID = C.ID;
SELECT  A.ID A.NAME B.ID B.DATE
FROM STUDENT A, REGISTER B
WHERE A.ID=B.ID;

 

 

6) CROSS JOIN

두 테이블간 JOIN조건이 없는경우 모든 경우의 데이터 조합을 말한다.

CARTESIAN PRODUCT나 CROSS PRODUCT라고 부르기도 한다.

SELECT  A.ID A.NAME B.ID B.NAME
FROM STUDENT A, PROFESSOR B
ORDER BY A.ID;

 

 

7)OUTER JOIN

LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN

해당 방향쪽으로 조인시 없는 데이터도 다 포함해서 출력된다.

 

 

 

 

 

 


오라클에서의 JOIN

LEFT OUTER JOIN

SELECT  A.ID A.NAME B.ID B.NAME
FROM STUDENT A, PROFESSOR B
WHERE A.ID = B.ID(+);

RIGHT OUTER JOIN

SELECT  A.ID A.NAME B.ID B.NAME
FROM STUDENT A, PROFESSOR B
WHERE A.ID = B.ID(+);

FULL OUTER JOIN은 표현할 수 없다.

 

 

 

 

 


집합 연산자

1) UNION (중복을 포함하지 않는 합집합)

중복되지 않는 데이터는 포함하지 않는다.

원래 있던 중복도 없어진다.

앞에나온 테이블 명을 따라간다.

SELECT ID, NAME
FROM STUDENT
UNION
SELECT ID, NAME
FROM OTHER_STUDENT;

2) UNION ALL (중복을 포함하는 합집합)

중복되는 데이터도 포함한다.

앞에나온 테이블 명을 따라간다.

SELECT ID, NAME
FROM STUDENT
UNION ALL
SELECT ID, NAME
FROM OTHER_STUDENT;

3) INTERSECT (교집합)

SELECT ID, NAME
FROM STUDENT
INTERSECT
SELECT ID, NAME
FROM OTHER_STUDENT;

4) MINUS (차집합)

SELECT ID, NAME
FROM STUDENT
MINUS
SELECT ID, NAME
FROM OTHER_STUDENT;

 

 

 

 


계층형 쿼리

상하 수직관계의 트리형태의 구조로 이루어진 형태

SELECT 컬럼
FROM 테이블명
WHERE 조건
START WITH 최상위 조건
CONNECT BY [NOCYCLE][PRIOR 계층형 구조 조건];

https://coding-factory.tistory.com/461 << 좋은 예시! 이해안가면 다시보기

 

[Oracle] 오라클 계층형 쿼리(START WITH.. CONNECT BY)

계층형 쿼리란? 계층형 구조는 상하 수직관계의 트리형태의 구조로 이루어진 형태를 말합니다. 예를 들자면 특정회사의 부서, 특정학교의 학과등이 있습니다. 계층형 쿼리는 테이블에 저장된

coding-factory.tistory.com

용어 기능
START WITH 최상위노드
CONNECT BY PRIOR A = B B->A방향으로 데이터가 전개됨
대체로 B가 부모, A가 자식이다
ORDER SIBLINGS BY 계층 내에서 정렬 가능

뷰(View)

장점

1. 독립성 : 테이블 구조가 변경되어도 뷰를 사용하는 응용프로그램은 변경하지 않아도 된다.

2. 편리성 : 복잡한 질의를 뷰로 생성함으로써 관련 질의를 단순하게 작성할 수 있다. 

3. 보안성 : 직원의 급여정보와 같이 숨기고 싶은 정보는 사용자로부터 감출 수 있다.

 

 


그룹함수

 

https://velog.io/@dongchyeon/%EC%98%A4%EB%9D%BC%ED%81%B4Oracle-%EA%B7%B8%EB%A3%B9-%ED%95%A8%EC%88%98-ROLLUP-CUBE-GROUPING-%EB%93%B1

 

[오라클(Oracle)] 그룹 함수 (ROLLUP, CUBE, GROUPING 등)

그룹 함수에 대해 정리해보자.

velog.io

https://myjamong.tistory.com/173

 

[Oracle] 오라클 GROUP BY ROLLUP, CUBE, GROUPING SETS 정리 :: 마이자몽

GROUP BY 특정 칼럼들을 기준으로 그룹화하여 합산, 평균, 최고값, 최소값 등의 수치를 확인하기 위해 GROUP BY 절을 이용합니다. 부서별 연봉 평균, 반 시험 최고 점수, 매장별 재고량과 같이 하나의

myjamong.tistory.com

 


옵티마이저와 실행계획

사용자가 질의한 SQL문에 대해 최적의 실행방법을 결정하는 역할

그리고 그 최적의 실행방법을 실행계획이라 한다.

어디까지나 계획이기 때문에 실제 정보와 다를 수 있다.

 

-규칙기반 옵티마이저(RBO, Rule Based Optimizer)

우선순위가 높은 규칙이 적은 일량으로 해당 작업을 수행하는 방법

제일 낮은 우선순위는 전체 테이블 스캔이고 제일 높은 우선순위는 ROWID,인덱스를 활용해서 테이블을 액세스하는 방법이다.

-비용기반 옵티마이저(Cost Based Optimizer)

SQL문을 실행하는데 소요될 처리시간 및 CPU, I/O 자원량 등을 계산하여 가장 효율적일 것으로 예상되는 실행계획을 선택

 


INDEX

원하는 데이터를 속도적인 측면에서 빠르게 찾을 수 있도록 만든 것

DML작업시 INDEX도 변경해야 하기 때문에 오히려 느려질 수 있음에 주의해야한다.

 

종류

1) B-트리 인덱스

   브랜치 블록과 리프블록으로 구성되며, 브랜치 블록은 분기를 목적으로 하고, 

   리프블록은 인덱스를 구성하는 컬럼의 값으로 정렬된다.

   일반적으로 OLTP시스템 환경에서 많이 사용된다.

 

2) 비트맵 인덱스

   시스템에 사용될 질의를 시스템 구현 시에 모두 알 수 없는 경우인 DW 및 AD-HOC 질의 환경을 위해서

   설계되었으며, 하나의 인덱스 키 엔트리가 많은 행에 대한 포인터를 저장하고 있는 구조

 

3) 클러스터드 인덱스

   인덱스의 리프 페이지가 곧 데이터 페이지이며, 리프 페이지의 모든 데이터는

   인덱스 키 컬럼 순으로 물리적으로 정렬되어 저장

  

 

DDL(Data Definition Language)

테이블과 같은 데이터 구조를 정의하는데 사용하는 명령어들

Oracle에서는 DDL명령후 자동 커밋을 수행하지만, MYSQL에서는 직접 커밋해주어야 한다.

 

1) CREATE

테이블 생성

테이블 이름 명명 조건 : 테이블과 컬럼명은 무조건 문자로 시작해야하고 특수문자는 " _ $ # "만 사용 가능

CREATE table 테이블이름(
	컬럼명 데이터타입 조건,
	컬럼명 데이터타입 조건,
      . . .
)
데이터타입 의미
CHAR 특정 문자열 개수 지정 ex) char(10)
VARCHAR 가변 문자열 지정 (현재 오라클 사용 안함)
VARCHAR2 가변 문자열 지정 (MYSQL, MariaDB지원 안함)
NUMBER 숫자 저장(정수, 실수) (MYSQL, MariaDB은 INT)
DATE 날짜에 사용하는 데이터 타입
제약조건 의미
NOT NULL Null을 허용하지 않음!
UNIQUE 중복 불가! (null은 가능!)
PRIMARY KEY 기본키로 지정한다는 뜻으로 테이블 당 하나만 가능
FOREGIN KEY 외래키로 지정한다는 뜻으로 references 키워드와 같이 쓰임
CHECK 컬럼에 입력되는 데이터를 체크해 특정 조건에 맞는 데이터만 입력 받음
DEFAULT 만약 값이 없으면 디폴트 값을 부여
참조동작 의미
RESTRICT 개체를 변경/삭제 때 다른 개체가 변경/삭제할 개체를 참조하고 있을 경우 취소(제한한다)
CASCADE 개체를 변경/삭제 때 다른 개체가 변경/삭제할 개체를 참조하고 있을 경우 함께 변경/삭제
NO ACTION MySQL에서는 RESTRICT와 동일
SET NULL 개체를 변경/삭제 때 다른 개체가 변경/삭제할 개체를 참조하고 있을 경우 참조하고 있는 값을
NULL로 세팅
AUTOMATIC 개체를 추가할 때 해당 테이블이 다른 테이블를 참조하고 있을 경우 참조하고 있는 값을
자동적으로 추가
DEPENDENT 개체를 추가할 때 해당 테이블이 다른 테이블를 참조하고 있을 경우 추가 불가

 

 

ex) Primary key

CREATE TABLE Student(
	ID VARCHAR(30) PRIMARY KEY,
    NAME VARCHAR(30),
    AGE NUMBER(10)
);

 

 

ex) Foregin key

CREATE TABLE Student(
	ID VARCHAR(30) PRIMARY KEY,
    NAME VARCHAR(30),
    AGE NUMBER(10),
    CONSTRAINT FK_ID FOREIGN KEY(NAME) REFERENCES NAMEINFO(NAME)
);

 

 

ex) Check

CREATE TABLE Student(
	ID VARCHAR(30),
    NAME VARCHAR(30),
    AGE NUMBER(10) CHECK(AGE IN(10,20,30)),
);

 

ex) Default

CREATE TABLE Student(
	ID VARCHAR(30),
    NAME VARCHAR(30) DEFAULT "JINNIE",
    AGE NUMBER(10)
);

주의!  만약, 직접 값을 Null로 지정한다면 디폴트 값으로 지정되지 않고, Null이 들어가게 된다.

 

 

 

인덱스 생성

데이터베이스로부터 매우 빠르게 데이터를 생성하고 검색하기 위해 사용

인덱스는 테이블의 단일 컬럼 또는 컬럼의 그룹을 사용함으로써 생성 가능하고, 인덱스가 생성되면 데이터를 정렬하기 전에 각 행마다 ROWID가 할당된다.

CREATE INDEX 인덱스테이블 ON 테이블(컬럼1, 컬럼2, ... );

 

 

 

 

 


2) ALTER

컬럼 추가

ALTER TABLE 테이블명 ADD 컬럼명 타입;
ALTER TABLE STUDENT ADD ADDRESS VARCHAR2(30) NOT NULL;

 

컬럼 타입 변경 > 이전에 있던 제약 조건도 사라질 수 있으니 주의! (똑같이 다시 지정해줘야함)

Oracle

ALTER TABLE 테이블명 MODIFY (컬럼명1 타입1 [DEFAULT] [NOT NULL], . . .);
ALTER TABLE STUDENT MODIFY NAME VARCHAR2(100);

MySQL 여러 컬럼 동시에 변경 불가

ALTER TABLE 테이블명 ALTER COLUMN 컬럼명 타입 [DEFAULT] [NOT NULL];
ALTER TABLE STUDENT ALTER COLUMN NAME VARCHAR2(100) NOT NULL;

 

컬럼 삭제

ALTER TABLE 테이블명 DROP 컬럼명;
ALTER TABLE STUDENT DROP NAME;

 

PRIMARY KEY 지정하기

ALTER TABLE STUDENT ADD PRIMARY KEY(ID);
ALTER TABLE STUDENT ADD CONSTRAINT student_pk PRIMARY KEY(ID);

 

 


3) RENAME

RENAME 테이블명 TO 새테이블명;

 

 


4) DROP

storage와 데이터 모두 삭제

DROP TABLE 테이블명;

 

 


5) TRUNCATE

최초 생성되었을 때의 storage만 남기고 데이터는 모두 삭제

TRUNCATE TABLE 테이블명;

 

 

 

 

 


TCL(Transcation Control Language)

1) COMMIT

문제가 없다고 판단하여 데이터를 데이터베이스에 반영시킴

COMMIT;

 

 


2) ROLLBACK

COMMIT이전의 상태로 돌아감

ROLLBACK;

 


3) SAVEPOINT

ROLLBACK이 가능한 저장점을 직접 지정할 때, 사용하는 명령어

Oracle

SAVEPOINT SVPT1;
ROLLBACK TO SVPT1;

MySQL

SAFE TRANSACTION SVTR1;
ROLLBACK TRANSACTION SVTR1;

 

 

 

 

 

 

 


DML

1) INSERT

INSERT INTO 테이블명 VALUES(모든 컬럼 등록);
INSERT INTO 테이블명(컬럼1, 컬럼2) VALUES(컬럼1값, 컬럼2값);

 

 


2) DELETE

삭제 데이터에 대한 로그가 남으며 storage도 남는다.

DELETE FROM 테이블명 where 조건;

 


3) UPDATE

UPDATE 테이블명 SET 컬럼명 = 값 where 조건;

 

 

 


4) SELECT

실행 작동 순서 

FROM >> WHERE >> GROUP BY >> HAVING >> SELECT >> ORDER BY

SELECT 컬럼 FROM 테이블 WHERE 조건;
조건 의미
BETWEEN a AND b a와 b값을 포함한 그 사이값
LIKE '비교문자열' 비교문자열과 형태가 일치한다(% , _ 사용)
IN (list) 리스트 내 값중 어느 하나와 일치
NOT 해당되지 않음 ex) WHERE NOT user_id = 1;
AND, OR 연산자 우선순위가 and에게 있다.
IS NULL 널인 경우
IS NOT NULL 널이 아닌 경우

연산자 우선순위

산술연산자 > 연결연산자(||) > 비교연산자 > IS NULL, LIKE ,IN > BETWEEN > NOT > AND > OR

 


내장함수(Built-in Function)

- 입력 행수에 따라 단일행 함수, 다중행 함수로 나뉜다.

- SELECT, WHERE, ORDER BY, UPDATE의 SET절에 사용 가능

- 단 하나의 결과만 리턴

 

1) 단일행 함수 : 단일행 값이 입력되는 함수

문자열 함수

문자열 함수 의미
ASCII(문자) 문자나 숫자를 아스키코드로 변환
CHAR(아스키번호) 아스키 번호를 문자나 숫자로 변환
LOWER(문자열)/UPPER(문자열) 대문자나 소문자로 변환
CONCAT(문자열1, 문자열2) 두 문자열을 결합
-> "||"(Oracle)이랑 "+"(MySQL)과 같은 의미이다
SUBSTR/SUBSTRING(문자열,m,n) 문자열에서 m위치부터 n개만큼 해당되는 문자열을 반환
-> n이 없다면 마지막 문자까지
-> m이 음수라면 마지막 문자로부터 m위치부터 n개 문자길이 반환
LENGTH/LEN(문자열) 문자열의 길이 반환
->공백이나 줄바꿈도 1로 친다

 

숫자형 함수

숫자형 함수 의미
SIGN(n) 숫자가 양수면 1, 음수면 -1, 0이면 0을 반환
MOD(n , m) n을 m으로 나눠서 나머지를 반환
CEIL/CEILING(n) 크거나 같은 최소 정수 반환
FLOOR(n) 작거나 같은 최대 정수 리턴

 

날짜형 함수

날짜형 함수 의미
SYSDATE/GETDATE() 현재날짜와 시각 출력
EXTRACT/DATEPART() 날짜에서 데이터 출력
TO_NUMBER(TO_CHAR(d,"YYYY"))/YEAR(d) 연도 출력

 

변환형 함수

변환형 함수 의미
TO_NUMBER(문자) 문자 데이터 타입을 숫자 데이터 타입으로 변환
TO_CHAR(숫자 혹은 날짜, [format]) 숫자 혹은 날짜 데이터 타입을 지정된 format의 문자 데이터 타입으로 변환
TO_DATE(문자열, format) 문자 데이터 타입을 지정된 format의 날짜 데이터 타입으로 변환 

 

NULL 관련 함수

NULL 관련 함수 의미
NVL(표현식1, 표현식2) 오라클
ISNULL(표현식1, 표현식2) MySQL
표현식1의 결과값이 null이면 표현식 2의 값을 출력
NULLIF(표현식1, 표현식2) 두 개의 값이 같으면 NULL을, 같지 않으면 첫 번째 값을 반환
COALESCE(표현식1, 표현식2, . . . ) NULL이 아닌 최초의 인자 값을 반환

+) NULL 의 연산

count 되지 않음, 연산시 NULL 리턴, 비교연산시 거짓 리턴

 

 

 

 


2)다중행 함수 : 다중행 값이 입력되는 함수

/* 문제설명 */

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15StKqAQkCFAYD&categoryId=AV15StKqAQkCFAYD&categoryType=CODE&problemTitle=%ED%95%98%EB%82%98%EB%A1%9C&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

로그인해야 볼 수 있습니다.

 

 

 


 

 

 

/* 풀이방법 */

프림 알고리즘을 사용해서 풀었다.

다만, 문제에 자세히 설명이 안되어져있어서 좀 헤맸는데, 유클리드 거리를 사용해서 두 섬 사이의 거리를 구한다는 점과 우선 터널의 길이를 구하고 맨 마지막에 다 더해서 반올림 한다는 점만 조심하면 괜찮았다.

https://jinniepark.tistory.com/46?category=956229 

 

[알고리즘 기본]PRIM 알고리즘

PRIM 알고리즘 MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다. 오늘은 프림 알고리즘에 대해 더 자세히 살펴보도록 하겠다. 프림 알고리즘을 시작점을 중

jinniepark.tistory.com

 

 

 

 

 

 

5개의 섬이 있는 예시를 하나 들자면 이렇다.

일단 힙에는 터널이 들어갈꺼다. 터널은 (목적지, 거리)형태로 넣어야하는데

어쩌피 다 그래프가 연결되어질꺼라는 가정이 있기 때문에 그냥 아무거나 넣으면 된다. 난 0번을 넣었다.

그럼 아래와 같은 형태가 된다. 아무곳도 아직 방문하지 않았고, Heap에는 초기값만 들어있는 상태이다.

우선순위큐는 거리가 최소가 되어야하기 때문에 거리를 기준으로 오름차순으로 정렬한다.

 

초기상태

 

 

 

 

 

그러면 일단 우선순위큐에서 값을 하나 꺼낸다. 

그리고 그 섬과 모든 섬과의 거리를 재서 큐에 넣는다. 큐는 당연히 자동으로 거리를 기준으로 오름차순으로 정렬해준다.

그리고 0번섬을 방문했음을 표시하고 가장 짧은 거리를 기록한다.

(코드에서는 기록하지는 않고 바로 total에 더했다)

 

 

 

 

 

 

 

위와 같은 과정을 반복하면된다.

다시 큐에서 꺼내고, 추가하고, 기록한다.

 

 

 

 

 

 

 

꺼내고 추가하고 기록

 

 

 

 

 

 

ㄲㄴㄱ ㅊㄱㅎㄱ ㄱㄹ

 

 

 

 

 

 

poll, offer, write

이렇게 모든 곳을 방문했으면 끝이당.

 

 

 

 

 

 

 


 

/* 해답코드 */

package samsung;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class b1251 {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		int T = Integer.parseInt(br.readLine());
		for(int t=1;t<=T;t++) {
			int N = Integer.parseInt(br.readLine());
			Island[] island = new Island[N];
			StringTokenizer xs = new StringTokenizer(br.readLine());
			StringTokenizer ys = new StringTokenizer(br.readLine());
			for(int n=0;n<N;n++) {
				int x = Integer.parseInt(xs.nextToken());
				int y = Integer.parseInt(ys.nextToken());
				island[n]=new Island(x,y);
			}
			double E = Double.parseDouble(br.readLine());
			
			PriorityQueue<Tunnel> q = new PriorityQueue<Tunnel>();
			boolean[] visited = new boolean[N];
			q.add(new Tunnel(0,0));
			int cnt=0;
			double total=0;
			while(!q.isEmpty()) {
				Tunnel tunnel = q.poll();
				if(visited[tunnel.dstn])continue;
				visited[tunnel.dstn]=true;
				
				
				total+=(tunnel.length*tunnel.length*E);
				for(int i=0;i<N;i++) {
					if(!visited[i]) {
						q.add(new Tunnel(i,getDistance(island[tunnel.dstn],island[i])));
					}
				} 
				if(++cnt==N)break;
				//System.out.printf("#%d %d %d\n",cnt,island[tunnel.dstn].x,island[tunnel.dstn].y);
			}
			
			System.out.format("#%d %.0f\n",t,total);
		}

	}
	private static double getDistance(Island i1, Island i2) {
		return Math.sqrt(Math.pow(i1.x-i2.x,2)+ Math.pow(i1.y-i2.y,2));
	}

}

class Island{
	public int x;
	public int y;
	public Island(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
}

class Tunnel implements Comparable<Tunnel>{
	public int dstn;
	public double length;
	public Tunnel(int dstn, double length) {
		super();
		this.dstn = dstn;
		this.length = length;
	}
	@Override
	public int compareTo(Tunnel o) {
		return Double.compare(this.length, o.length);
	}
}

'Coding Test > SWEA' 카테고리의 다른 글

[SWEA]Flatten  (0) 2021.08.05
[SWEA]Ladder1  (0) 2021.08.05

/* 문제설명 */

N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다.

아기 상어와 물고기는 모두 크기를 가지고 있고, 이 크기는 자연수이다. 가장 처음에 아기 상어의 크기는 2이고, 아기 상어는 1초에 상하좌우로 인접한 한 칸씩 이동한다.

아기 상어는 자신의 크기보다 큰 물고기가 있는 칸은 지나갈 수 없고, 나머지 칸은 모두 지나갈 수 있다. 아기 상어는 자신의 크기보다 작은 물고기만 먹을 수 있다. 따라서, 크기가 같은 물고기는 먹을 수 없지만, 그 물고기가 있는 칸은 지나갈 수 있다.

아기 상어가 어디로 이동할지 결정하는 방법은 아래와 같다.

  • 더 이상 먹을 수 있는 물고기가 공간에 없다면 아기 상어는 엄마 상어에게 도움을 요청한다.
  • 먹을 수 있는 물고기가 1마리라면, 그 물고기를 먹으러 간다.
  • 먹을 수 있는 물고기가 1마리보다 많다면, 거리가 가장 가까운 물고기를 먹으러 간다.
    • 거리는 아기 상어가 있는 칸에서 물고기가 있는 칸으로 이동할 때, 지나야하는 칸의 개수의 최솟값이다.
    • 거리가 가까운 물고기가 많다면, 가장 위에 있는 물고기, 그러한 물고기가 여러마리라면, 가장 왼쪽에 있는 물고기를 먹는다.

아기 상어의 이동은 1초 걸리고, 물고기를 먹는데 걸리는 시간은 없다고 가정한다. 즉, 아기 상어가 먹을 수 있는 물고기가 있는 칸으로 이동했다면, 이동과 동시에 물고기를 먹는다. 물고기를 먹으면, 그 칸은 빈 칸이 된다.

아기 상어는 자신의 크기와 같은 수의 물고기를 먹을 때 마다 크기가 1 증가한다. 예를 들어, 크기가 2인 아기 상어는 물고기를 2마리 먹으면 크기가 3이 된다.

공간의 상태가 주어졌을 때, 아기 상어가 몇 초 동안 엄마 상어에게 도움을 요청하지 않고 물고기를 잡아먹을 수 있는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 공간의 크기 N(2 ≤ N ≤ 20)이 주어진다.

둘째 줄부터 N개의 줄에 공간의 상태가 주어진다. 공간의 상태는 0, 1, 2, 3, 4, 5, 6, 9로 이루어져 있고, 아래와 같은 의미를 가진다.

  • 0: 빈 칸
  • 1, 2, 3, 4, 5, 6: 칸에 있는 물고기의 크기
  • 9: 아기 상어의 위치

아기 상어는 공간에 한 마리 있다.

출력

첫째 줄에 아기 상어가 엄마 상어에게 도움을 요청하지 않고 물고기를 잡아먹을 수 있는 시간을 출력한다.

 

 

 


 

 

 

/* 풀이방법 */

 

문제를 똑바로 안읽어서 고생했다. 한마리 먹을 때마다 몸집이 커지는게 아니라 자신의 몸집 크기만큼 먹었을때 사이즈가 증가한다. 제발 문제좀 제대로 읽자.

 

최단경로를 구해야하므로 기본적으로 BFS알고리즘을 사용했다.

 

물고기의 우선순위를 정하는 법이 상당히 까다로웠는데, 처음에는 방향 순회 순서로 우선순위를 정하고자 하였으나,

 

방향 순회 순서로 절때 구할 수 없다. 따라서 만약에 먹이타겟이 발견되면 그 같은 길이에 있는 곳까지 탐색한 후 직접 일일이 좌표를 비교해줘야 했다..

 

그점만 유의하면 쉽게 풀 수 있다.

 

 

(+) 시간을 줄일 아이디어

아마 우선순위 큐 사용하면 훨씬더 속도면에서 개선될 듯하다.

 

 


 

/* 해답코드 */

package baekjoon;

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

//아기상어
public class b16236 {
	public static int N;
	public static int[][] map;
	public static int[] dx = { -1, 0, 0, 1 };// 상, 좌, 우, 하
	public static int[] dy = { 0, -1, 1, 0 };// 상, 좌, 우, 하

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		N = Integer.parseInt(br.readLine());
		map = new int[N][N];
		Fish shark = null;
		for (int n = 0; n < N; n++) {
			st = new StringTokenizer(br.readLine());
			for (int m = 0; m < N; m++) {
				map[n][m] = Integer.parseInt(st.nextToken());
				if (map[n][m] == 9) {
					shark = new Fish(n, m, 2);
					map[n][m] = 0;
				}
			}
		}
		System.out.println(bfs(shark));
	}

	private static int bfs(Fish shark) {
		while (true) {
			Queue<Integer[]> q = new LinkedList<>();
			int[][] visited = new int[N][N];
			List<Fish> fishList = new ArrayList<>();
			q.add(new Integer[] { shark.x, shark.y });
			boolean findFish = false;
			while (!q.isEmpty()) {
				Integer[] point = q.remove();
				int x = point[0];
				int y = point[1];
				// System.out.printf("%d %d\n",x,y);
				if (map[x][y] < shark.size && map[x][y] != 0) {
					Fish f = new Fish(x, y);
					f.dist = visited[x][y];
					fishList.add(f);
					findFish = true;
				}
				if (!findFish) {
					for (int d = 0; d < 4; d++) {
						int nx = x + dx[d];
						int ny = y + dy[d];
						if (nx >= 0 && nx < N && ny >= 0 && ny < N && map[nx][ny] <= shark.size
								&& visited[nx][ny] == 0) {
							visited[nx][ny] = visited[x][y] + 1;
							q.add(new Integer[] { nx, ny });
						}
					}
				}
			}

			if (fishList.size() == 0)
				return shark.time;
			else {
				Collections.sort(fishList);
				Fish f = fishList.remove(0);
				map[f.x][f.y] = 0;
				shark.cnt++;
				if (shark.size == shark.cnt) {
					shark.cnt = 0;
					shark.size++;
				}
				shark.x = f.x;
				shark.y = f.y;
				shark.time += visited[f.x][f.y];
				//System.out.printf("##%d %d %d\n", f.x, f.y, shark.time);
			}

		}
	}
}

class Fish implements Comparable<Fish> {
	public int size;
	public int x;
	public int y;
	public int cnt;
	public int time;
	public int dist;

	public Fish() {
	}

	public Fish(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public Fish(int x, int y, int size) {
		this.cnt = 0;
		this.time = 0;
		this.size = size;
		this.x = x;
		this.y = y;
	}

	@Override
	public int compareTo(Fish o) {
		if (this.dist == o.dist) {
			if (this.x == o.x) {
				return this.y - o.y;
			} else
				return this.x - o.x;
		} else
			return this.dist - o.dist;
	}
}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][1922]네트워크 연결  (0) 2021.09.17
[백준][12865]평범한 베낭  (0) 2021.09.07
[백준][1197]최소 스패닝 트리  (0) 2021.08.24
[백준][1987]알파벳  (1) 2021.08.19
[백준][3109]빵집  (0) 2021.08.19

/* 문제설명 */

최소 스패닝 트리는, 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리를 말한다.

입력

첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이 가중치 C인 간선으로 연결되어 있다는 의미이다. C는 음수일 수도 있으며, 절댓값이 1,000,000을 넘지 않는다.

그래프의 정점은 1번부터 V번까지 번호가 매겨져 있고, 임의의 두 정점 사이에 경로가 있다. 최소 스패닝 트리의 가중치가 -2,147,483,648보다 크거나 같고, 2,147,483,647보다 작거나 같은 데이터만 입력으로 주어진다.

출력

첫째 줄에 최소 스패닝 트리의 가중치를 출력한다.

 

 

 

 


 

 

 

/* 풀이방법 */

PRIM알고리즘을 사용해서 풀이했다.

https://jinniepark.tistory.com/46

 

[알고리즘 기본]PRIM 알고리즘

PRIM 알고리즘 MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다. 오늘은 프림 알고리즘에 대해 더 자세히 살펴보도록 하겠다. 프림 알고리즘을 시작점을 중

jinniepark.tistory.com

 

 

 

 

 


 

/* 해답코드 */

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

//최소 스피닝 트리
public class Main {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st =new StringTokenizer(br.readLine());
		int V = Integer.parseInt(st.nextToken());
		int E = Integer.parseInt(st.nextToken());
		
		ArrayList<Edge>[] adjList = new ArrayList[V+1];
		for(int i=1;i<=V;i++) {
			adjList[i] = new ArrayList<Edge>();
		}
		for(int i=0;i<E;i++) {
			st =new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			int w = Integer.parseInt(st.nextToken());
			adjList[s].add(new Edge(e,w));
			adjList[e].add(new Edge(s,w));
		}
		
		int[] min_edge = new int[V+1];
		Arrays.fill(min_edge, Integer.MAX_VALUE);
		boolean[] visited = new boolean[V+1];
		PriorityQueue<Edge> q = new PriorityQueue<Edge>();
		q.add(new Edge(1,0));
		
		int cnt=0;
		while(!q.isEmpty()) {
			Edge edge = q.poll();
			if(visited[edge.n])continue;
			
			visited[edge.n]=true;
			min_edge[edge.n] = edge.dist;
			for(Edge next : adjList[edge.n]) {
					if(!visited[next.n]) {
						q.add(next);
				}
			}
			if(++cnt==V)break;
		}
		int sum=0;
		for(int i=1;i<=V;i++) {
			sum+=min_edge[i];
		}
		System.out.println(sum);
	}
}


class Edge implements Comparable<Edge>{
	int n;
	int dist;
	public Edge(int n, int dist) {
		super();
		this.n = n;
		this.dist = dist;
	}

	@Override
	public int compareTo(Edge o) {
		return Integer.compare(this.dist, o.dist);
	}
}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][12865]평범한 베낭  (0) 2021.09.07
[백준][16236]아기상어  (0) 2021.08.25
[백준][1987]알파벳  (1) 2021.08.19
[백준][3109]빵집  (0) 2021.08.19
[백준][1992]쿼드트리  (0) 2021.08.18

PRIM 알고리즘

MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다.

오늘은 프림 알고리즘에 대해 더 자세히 살펴보도록 하겠다.

 

프림 알고리즘을 시작점을 중심으로 방문 가능한 모든 정점을 방문해서 가장 최소 가중치를 가지는 노드와 연결하고,

이를 모든 정점을 방문할 때 까지 반복함으로써 최소 신장 트리를 구한다.

 

크루스칼은 프림에 비해 희소 그래프인 경우, 그러니까 간선이 적은 경우 적합하고,

프림은 크루스칼에 비해 간선이 많이 존재하는 밀집그래프에 더 적합하다.

 

크루스칼 알고리즘은 아래에서 더 자세하게 다룬다.

https://jinniepark.tistory.com/55

 

[알고리즘 기본]Kruskal 알고리즘

Kruskal 알고리즘 MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다. 오늘은 크루스칼 알고리즘에 대해 더 자세히 살펴보도록 하겠다. 크루스칼 알고리즘은

jinniepark.tistory.com

 

일단을 개념적으로 구하는 방법을 그려보았다.


예시)

 

 

초기 상태이다. 해당 정점을 방문했는지 체크할 visited배열과 가장 작은 가중치를 가질 Min_edge배열이 존재한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

하지만 위와 같은 방법으로 구현 할 때 인접해 있는 노드를 탐색하고 또 그 가중치를 비교하는 과정에서 정렬/비교를 하면 (주변 정점 수)-1번 만큼 연산이 이루어져야한다. 이는 많은 노드와 정점이 있다면 시간복잡도를 늘리는 원인이 된다.

따라서 실제 구현할때는 우선순위 큐를 사용해서 시간복잡도를 줄여야한다. 

 

아래에 우선순위 큐를 추가한 구현방법을 확인해보겠다.

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


관련문제

https://www.acmicpc.net/problem/1197

 

1197번: 최소 스패닝 트리

첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이

www.acmicpc.net

https://jinniepark.tistory.com/47

 

[백준][1197]최소 스패닝 트리

/* 문제설명 */ 최소 스패닝 트리는, 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리를 말한다. 입력 첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선

jinniepark.tistory.com

 

+ Recent posts