다익스트라 알고리즘

  • 그래프의 한 정점에서 모든 정점까지의 최단거리를 각각 구하는 알고리즘
  • 음의 가중치X
  • 시간 복잡도 O((V+E)logV) V=정점 개수, E=한 정점의 주변노드

 

예시

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
 
 
public class Main{
    
    public static class Node{
        int v,w;
 
        public Node(int v, int w) {
            this.v = v;
            this.w = w;
        }
    }
    static List<Node> list[];
    static int [] distance;
    static boolean []visited;
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        int N = Integer.parseInt(br.readLine());
        int M = Integer.parseInt(br.readLine());
        
        list =new ArrayList[N+1];
        distance = new int [N+1];
        visited = new boolean[N+1];
        
        for(int i=1;i<N+1;i++) list[i]= new ArrayList<>();
        
        for(int i=0;i<M;i++) {
            st = new StringTokenizer(br.readLine()," ");
            int start = Integer.parseInt(st.nextToken());
            int arrive = Integer.parseInt(st.nextToken());
            int price = Integer.parseInt(st.nextToken());
            list[start].add(new Node(arrive,price));
        }
        
        st = new StringTokenizer(br.readLine()," ");
        int go = Integer.parseInt(st.nextToken()); //시작점
        int end = Integer.parseInt(st.nextToken()); //도착점
        
        Arrays.fill(distance, Integer.MAX_VALUE);
        distance[go] = 0; //시작점 0으로
        
        int min, current = 0;
        for(int i=0; i<N;i++) {
            min = Integer.MAX_VALUE;
            current = -1;
            for(int j=1;j<N+1;j++) { //거리가 가장짧은 정점찾기
                if(!visited[j] && distance[j]<min) {
                    min = distance[j];
                    current =j;
                }
            }
            if(current == end) break;
            
            for(Node next : list[current]) { //찾은 정점과 연결된 정점들의 거리 저장
                if(!visited[next.v] && distance[next.v]> distance[current]+next.w) {
                    distance[next.v] = distance[current] + next.w;
                }
            }
            visited[current] = true;
        }
        System.out.println(distance[end]);
    }
}
cs

 

 

'정리 > 자료구조+알고리즘' 카테고리의 다른 글

투 포인터(Two Pointer)  (0) 2021.08.26
이진 탐색 (Binary Search) 알고리즘  (0) 2021.07.05
세그먼트 트리(Segment Tree)  (0) 2021.07.01
위상정렬  (0) 2021.06.18
비트마스크 (BitMask)  (0) 2021.04.21

투 포인터 알고리즘

  • 1차원 배열에서 두 개의 포인터를 조작해가면서 원하는 결과를 얻는 알고리즘이다.
  • 투 포인터 알고리즘을 이용해 O(N^2)에서 O(NlogN)으로 개선할 수 있다.

 

예시

  • SUM =5 인 경우의 수 구하기

  • 위의 과정을 배열의 인덱스가 N일때 즉 모두 확인했을 때 반복문 종료!

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package twoPointer;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main_BJ_2003_수들의합2 {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        
        int [] arr = new int[N];
        
        st = new StringTokenizer(br.readLine());
        for(int i=0;i<N;i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }
        
        int start=0, end=0, sum=0, cnt=0;
        while(true) {
            if(sum>=M) sum -= arr[start++];
            else if(end==N) break;
            else sum += arr[end++];
            
            if(sum==M) cnt++;
        }
        System.out.println(cnt);
    }
 
}
 
cs

 

 

 

'정리 > 자료구조+알고리즘' 카테고리의 다른 글

다익스트라(Dijkstra) 알고리즘  (0) 2021.09.04
이진 탐색 (Binary Search) 알고리즘  (0) 2021.07.05
세그먼트 트리(Segment Tree)  (0) 2021.07.01
위상정렬  (0) 2021.06.18
비트마스크 (BitMask)  (0) 2021.04.21

이진탐색 알고리즘

  • 오름차순으로 정렬된 정수의 리스트를 같은 크기의 두 부분 리스트로 나누고 필요한 부분에서만 탐색하도록 제한하여 원하는 원소를 찾는 알고리즘
  • 리스트의 중간 부분에 찾는 원소가 있는지 확인 후, 왼쪽에 있는지 오른쪽에 있는지 판단하여 검색
  • 즉, 자료를 반으로 나누어 탐색하는 방법
  • 시간복잡도 : O(logN)

예시

  • 찾고자 하는 값을 찾을 때까지 과정 반복!
  • 이진 탐색 알고리즘을 사용할때는 반드시 정렬된 자료에만 사용해야한다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
public static int binarySearch(int arr[], int left, int right, int key) { //반복문
        
        while(left<right) {            
            int mid = (left+right)/2;
            if(key==arr[mid]) //탐색 성공
                return mid;
            else if(key>arr[mid]) //중간 원소보다 크면
                left = mid+1;
            else //중간 원소보다 작으면
                right = mid-1;
        }
        return -1;
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
public static int binarySearch(int arr[], int left, int right, int key) { //재귀문
        
        if(left>right) return -1;
        int mid = (left+right)/2;
        if(arr[mid]==key) //탐색 성공
            return mid;
        else if(key>arr[mid]) // 중간 원소보다 크면
            return binarySearch(arr,mid+1,right,key);
        else // 중간 원소보다 작으면
            return binarySearch(arr,left,mid-1,key);
}
cs

 

 

 

'정리 > 자료구조+알고리즘' 카테고리의 다른 글

다익스트라(Dijkstra) 알고리즘  (0) 2021.09.04
투 포인터(Two Pointer)  (0) 2021.08.26
세그먼트 트리(Segment Tree)  (0) 2021.07.01
위상정렬  (0) 2021.06.18
비트마스크 (BitMask)  (0) 2021.04.21

세그먼트 트리(Segment Tree) 

  • 특정 구간 내 연산에 대해서 빠르게 응답하기 위해 만들어진 자료구조
    - 1,2,3,4,5라는 수들 중 2번째부터 5번째까지의 합을 구하고 싶다!
       = 배열로 구간합을 저장하고 sum[5] - sum[1]으로 구할 수 있다. -> 시간 복잡도 : O(1)

    - 만약 배열의 값이 바뀐다면?
      = 바뀔때마다 구간합을 더해서 다시 저장해야한다. -> 시간 복잡도 : O(N^2)

    - 세그먼트 트리를 사용했을 경우에는 시간 복잡도 O(NlogN)

 

  • 세그먼트 트리 만들기

 

 

 

 

구현

    • 트리 만들기
1
2
3
4
5
public static int init(int node_idx, int start, int end) {
        if(start==end) return tree[node_idx] = arr[start]; //start == end인 경우 : leaf노드

// 자식노드를 더한다 (왼쪽 노드 + 오른쪽 노드)
        return tree[node_idx] = init(node_idx*2, start, (start+end)/2+ 
init(node_idx*2+1, (start+end)/2+1, end);
}
cs

 

    • 배열 값 변경 (구간합 수정)
1
2
3
4
5
6
7
8
9
10
public static void update(int node_idx, int start, int end, int idx, long diff) {
        if(idx < start | idx> end) return;
 
        tree[node_idx]+=diff;
 
        if(start!=end) {
            update(node_idx*2,start,(start+end)/2,idx,diff);
            update(node_idx*2+1, (start+end)/2+1, end, idx, diff);
        }
}
cs

 

    • 구간합 구하기
1
2
3
4
5
6
7
8
9
public static int sum(int node_idx, int start, int end, int L, int R) {
        if(end<|| start>R) return 0;
        
        if(L<=start && end<=R) return tree[node_idx];
        
        return sum(node_idx*2, start, (start+end)/2,L,R) + 
sum(node_idx*2+1, (start+end)/2+1, end, L,R);
        
}
 
cs

 

세그먼트 트리 관련 문제

 

2042번: 구간 합 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄

www.acmicpc.net

 

 

 

'정리 > 자료구조+알고리즘' 카테고리의 다른 글

투 포인터(Two Pointer)  (0) 2021.08.26
이진 탐색 (Binary Search) 알고리즘  (0) 2021.07.05
위상정렬  (0) 2021.06.18
비트마스크 (BitMask)  (0) 2021.04.21
최소신장트리(MST) 알고리즘  (0) 2021.03.26

위상정렬이란?

  • 여러 일들에 순서가 정해져 있을 때 순서에 맞게끔 나열하는 것
    • 방향 그래프
    • 그래프의 순환 x

예시

 

 

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class Main_ {
    
    
    static int N,M;
    static ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
    static int [] indegree;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        
        indegree = new int[N+1];
        
        for(int i=0;i<=N;i++) list.add(new ArrayList<>());
        
        for(int i=0;i<M;i++) {
            st = new StringTokenizer(br.readLine());
            
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            
            list.get(a).add(b);
            indegree[b]++;
        }
        sort();
    }
    
    public static void sort() {
        Queue<Integer> queue = new LinkedList<>();
        Queue<Integer> result = new LinkedList<>();
        
        for(int i=1;i<N+1;i++) {
            if(indegree[i]==0) {
                queue.add(i);
            }
        }
        
        while(!queue.isEmpty()) {
            int temp = queue.poll();
            result.add(temp);
            
            for(Integer item : list.get(temp)) {
                indegree[item]--;
                if(indegree[item]==0) {
                    queue.add(item);
                }
            }
        }
        while(!result.isEmpty()) {
            System.out.print(result.poll()+" ");
        }
    }
 
}
cs

 

 

비트마스크(BitMask)란?

  • 비트 필드에서 비트 연산에 사용되는 데이터로 정수의 이진수 표현을 자료 구조로 쓰는 기법을 말한다.
  • 이진수는 0과 1로 표현
  • 비트연산을 통해 삽입, 삭제, 조회 등이 간단해지며 더 빠른 연산이 가능해진다.

 

연산자

 

 

 

최소신장트리(MST)란?

  • 무향 가중치 그래프에서 신장트리를 구성하는 간선들의 가중치 합이 최소인 신장트리
    • Kruskal 알고리즘
    • Prim 알고리즘

 

Kruskal

  • 간선을 하나씩 선택해서 MST를 찾는 알고리즘
    1. 모든 간선을 가중치에 따라 오름차순 정렬
    2. 가중치가 낮은 순서대로 간선을 선택하며 사이클이 발생하지 않도록 간선 선택
    3. N-1개의 간선이 선택될 때까지 2번 반복 수행


  • 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
 
public class Kruskal {
    static class Edge implements Comparable<Edge>{
        int start, end, weight;
 
        public Edge(int start, int end, int weight) {
            this.start = start;
            this.end = end;
            this.weight = weight;
        }
 
        @Override
        public int compareTo(Edge o) {
            return this.weight-o.weight;
        }
    }
    
    static int V,E,A,B,C;
    static int [] parents;
    static Edge[] edgeList;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine()," ");
        
        V = Integer.parseInt(st.nextToken());
        E = Integer.parseInt(st.nextToken());
        
        parents = new int[V+1];
        edgeList = new Edge[E];
        
        for(int i=0;i<E;i++) {
            st = new StringTokenizer(br.readLine()," ");
            A = Integer.parseInt(st.nextToken());
            B = Integer.parseInt(st.nextToken());
            C = Integer.parseInt(st.nextToken());
            
            edgeList[i] = new Edge(A,B,C);
        }
        
        make();
        
        Arrays.sort(edgeList);
        int result = 0, count=0;
        for(Edge edge : edgeList){
            if(union(edge.start,edge.end)){ // 싸이클이 발생하지 않았으면
                result += edge.weight;
                count++;                
                if(count == V-1){ // 연결 간선수가 정점수-1이면 다 연결
                    break;
                }            
            }
        }
        System.out.println(result);
 
    }
    
    public static void make() {
        for(int i=0;i<V;i++) parents[i]= i;
    }
    
    public static boolean union(int a, int b) {
        int aRoot = find(a);
        int bRoot = find(b);
        
        if(aRoot != bRoot) {
            parents[bRoot] = aRoot;
            return true;
        }
        return false;
    }
    
    public static int find(int x) {
        if(parents[x]==x) return x;
        return parents[x]= find(parents[x]);
    }
 
}
cs

 

Prim

  • 하나의 정점에서 연결된 간선들 중에 하나씩 선택하면서 MST를 만들어가는 방식
    1. 임의 정점을 하나 선택
    2. 선택한 정점과 인접하는 정점들 중에 최소 비용 간선이 존재하는 장점 선택
    3. 모든 정점이 선택될 때 까지 1, 2번 반복


  • 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
 
public class Prim{
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine().trim());
        int[][] input = new int[N][N];
        boolean[] visited = new boolean[N];
        int[] minEdge = new int[N];
        
        StringTokenizer st;
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < N; j++) {
                input[i][j] = Integer.parseInt(st.nextToken());
            }
            minEdge[i] = Integer.MAX_VALUE;
        }// i노드에서 j노드까지의 비용을 모두 배열에 저장
        
        int minVertex,min,result = 0;
        minEdge[0= 0// 임의의 시작점 비용 0 셋팅
        
        for(int c = 0 ; c< N; c++){// 모든 정점 수만큼 반복
            min = Integer.MAX_VALUE;// 초기값으로 정수의 최대치를 주고 시작
            minVertex = 0;
            
            for(int i=0; i<N; ++i) { 
                if(!visited[i] &&  min > minEdge[i] ) {
                    min = minEdge[i];
                    minVertex = i;
                }
            }    
            
            result += min; 
            visited[minVertex] = true
            
            for (int i = 0; i < N; i++) { 
                if (!visited[i] && input[minVertex][i] != 0 &&  minEdge[i] > input[minVertex][i]  ) {
                    minEdge[i] = input[minVertex][i];
                }
            }
        }
        System.out.println(result);
    }
}
cs

'정리 > 자료구조+알고리즘' 카테고리의 다른 글

이진 탐색 (Binary Search) 알고리즘  (0) 2021.07.05
세그먼트 트리(Segment Tree)  (0) 2021.07.01
위상정렬  (0) 2021.06.18
비트마스크 (BitMask)  (0) 2021.04.21
Floyd Warshall (플로이드 와샬) 알고리즘  (0) 2021.03.25

Floyd Warshall 

  • 모든 정점에서 모든 정점으로의 최단 경로를 찾는 알고리즘
  • Dijkstra 알고리즘과 다르게 한 장점으로부터 모든 정점으로의 최단경로가 아닌 모든 정점 사이의 최단경로를 구한다는 점과 음수 가중치가 있어도 최단 경로를 구할 수 있다점에서 다익스트라 알고리즘과 차이점이있다.

 

최단경로 찾는 과정

  • 출발지에서 목적지로 가는 경우와 출발지에서 경유지를 통해 목적지를 가는 경우를 비교해 둘 중 더 빠른 경우가 존재한다면 더 빠른 경우로 최단 거리를 계산한다.

 

구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main {
    static int[][] distance;
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
 
        st = new StringTokenizer(br.readLine(), " ");
        int N = Integer.parseInt(st.nextToken());
 
        distance = new int[N][N];
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine()," ");
            for (int j = 0; j < N; j++) {
                distance[i][j] = Integer.parseInt(st.nextToken());
                if (i != j && distance[i][j] == 0)
                    distance[i][j] = 99999;
            }
        }
        // 경유지 -> 출발지 -> 목적지 순
        for (int k = 0; k < N; k++) { //경유지
            for (int i = 0; i < N; i++) { //출발지
                if (i == k) continue;
                for (int j = 0; j < N; j++) { //도착지
                    if (distance[i][k] + distance[k][j] < distance[i][j]) {
                        distance[i][j] = distance[i][k] + distance[k][j];
                    }
                }
            }
        }
 
        System.out.println("================ folyd warshall ================ ");
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                System.out.print(distance[i][j] + " ");
            }
            System.out.println();
        }
 
    }
 
}
cs

<결과>

 

 

'정리 > 자료구조+알고리즘' 카테고리의 다른 글

이진 탐색 (Binary Search) 알고리즘  (0) 2021.07.05
세그먼트 트리(Segment Tree)  (0) 2021.07.01
위상정렬  (0) 2021.06.18
비트마스크 (BitMask)  (0) 2021.04.21
최소신장트리(MST) 알고리즘  (0) 2021.03.26

+ Recent posts