[Algorithm] Algorithm 다익스트라

최단경로

최단경로 정의

  • 간선의 가중치가 있는 그래프에서 두 정점 사이의 경로들 중에 간선의 가중치의 합이 최소인 경로.

하나의 시작정점에서 끝 정점까지의 최단경로.

  • 다익스트라 알고리즘 -> 음의 가중치를 허용하지 않음
  • 벨만 포드 알고리즘 -> 음의 가중치 허용

  • 모든 정점에 대한 최단경로 -> 플로이드 와셜 알고리즘.

20210322_112458

아직 고려되지 않은 정점 중 시작점에서 자신에게 오는 가장 가까운 애를 먼저 찾음. 처리되지 않은 애들 중.


다익스트라 알고리즘

-시작 정점에서의 거리가 최소인 정점을 선택해 나가면서 최단 경로를 구하는 방식.

  • 탐욕기법을 사용한 알고리즘으로 MST의 프림 알고리즘과 유사.

선택이 안 된 것 중 하나 선택.

w를 u에 합침.

d[v]는 아직 방문 안한 v에 대해 얘기하는데 이 둘중 어느게 더 작은가.

1과 0 중 연결된 애들중 제일 작은 값.

20210322_152245

​!visited[j] : 아직 선택하지 않은 곳 / adjMatrix[current][j] != 0 : 자기자신으로 가는 경우가 아닐 때 / distance[j] > min + adjMatrix[current][j] : 최소비용과 현재 값의 값이 더 최적이라면 이라고 이해했습니다!!!

인접한 경우에만 가중치 값이 존재하니까 꼭 필요한 것 같아요!

​ adjMatrix[current][j] != 0 : 자기자신으로 가는 경우가 아닐 때 ==> 자기 자신보다는 연결이 되어 있는 경우만 이 더 좋아 보이내요

인접행렬이여서 자기 자신인 0을 확인했고 인접리스트로 구현한다면 확인하지 않고도 코드 작성할 수 있어요

왜 pq를 쓰는지 아는게 중요하다 최소값 정점 빠르게 찾기 위해 o(1)만에 꺼내는 느낌으로 코드 짠다.

20210322_154957

20210322_155050

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

public class Dijkstra {
	public static void main(String[] args) throws NumberFormatException, IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int V = Integer.parseInt(br.readLine());
		int start = 0; //출발점
		int end = V-1;	//도착점.
		int [][] adjMatrix = new int[V][V];//인접행렬

		StringTokenizer st = null;
		for(int i =0; i<V;i++) {
			st = new StringTokenizer(br.readLine()," ");
			for(int j  =0; j<V;j++) {
				adjMatrix[i][j] = Integer.parseInt(st.nextToken());
			}
		}

		int [] distance = new int[V];
		boolean [] visited = new boolean[V];

		Arrays.fill(distance, Integer.MAX_VALUE);
		distance[start] = 0;

		for(int i =0; i<V;i++) {
			//step1. 처리하지 않은 정점 중 출발지에 가장 가까운 정점 선택
			int min = Integer.MAX_VALUE;
			int current=0; //min의 최소비용에 해당하는 정점번호.
			for(int j =0; j<V; j++) {
				if(!visited[j] && min > distance[j]) {
//					distance의 값 중 최소의 값을 찾아야 하니까.
					min = distance[j];
					current = j;
				}
			}

			visited[current] = true;
			if(current== end)break; //끝이면 다른곳으로 경유해서 거쳐서 가는 애를 찾을 필요 없다.
			//출발지에서 목적지 가는 모든 경우 비교할 거아니면 여기서 끝내도 된다.
			//step2. 선택된 current를 경유지로 하여 아직 처리하지 않은 다른 정점으로 최소비용을 따져본다.
			for(int j =0; j<V;j++) {
				if(!visited[j] && adjMatrix[current][j]!=0 && distance[j]>min+adjMatrix[current][j]) {
					//출발지에서 current까지 더한게 최소비용 . 출발지에서 j로 오는 비용보다 크면 원래 거보다 거쳐서 오는게 더 유용하다는 의미니까
					distance[j] = min+adjMatrix[current][j];
				}

			}
		}
		System.out.println(distance[end]);
		//만약 출발지에서 어떤 경유로 가도 end 못가면 max_value
		//그래서 초기값인 maxvalue면 어떤 식으로 해도 목적지에 못간다.
	}
}

KMP 알고리즘도 Knuth-Morris-Pratt Algorithm

  • 불일치가 발생한 텍스트 문자열의 앞 부분에 어떤 문자가 있는지 미리 알고 있으므로 불일치가 발생한 앞 부분에 대해 다시 비교하지 않고 매칭을 수행.

  • 패턴을 전처리 해 배열 fail[k]를 구해 잘못된 시작을 최소화함. -> fail[k]: k인덱스에서 일치하는 접두사와 접미사가 일치하는 최대 길이. 시간 복잡도 : O(M+N);

ex)

20210322_155104

패턴 매칭에 사용되는 알고리즘

  1. 고지식한 패턴 검색 알고리즘(브루트포스)
  2. 라빈 - 카프 알고리즘
  3. 보이어- 무어 알고리즘
  4. kmp 알고리즘.

20210322_155207 20210322_155333

kmp는 틀린 부분 발생했을 떄 거기서 부터 앞은 맞은 부분을 두고 틀린부분 부터 이 정보로 맨앞으로 돌아가는게 아니라 틀린애 대신에 밀어서 그 자리에서 최대한 비교. 안되면 다음으로 감.

fail이라 적어놨는데(실패함수) 사실 함수가 아니라 문자열의 비교에 실패했을 시 이 패턴포인터가 어느위치로 가야하는지 알려줘야하는 길잡이 배열.


KMP 알고리즘

20210322_160220

20210322_160300

20210322_160316





© 2021.03. by yacho

Powered by github