CheerUp_Cheers

벨만 포드 본문

알고리즘

벨만 포드

meorimori 2020. 4. 19. 23:02

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

 

11657번: 타임머신

첫째 줄에 도시의 개수 N (1 ≤ N ≤ 500), 버스 노선의 개수 M (1 ≤ M ≤ 6,000)이 주어진다. 둘째 줄부터 M개의 줄에는 버스 노선의 정보 A, B, C (1 ≤ A, B ≤ N, -10,000 ≤ C ≤ 10,000)가 주어진다. 

www.acmicpc.net

#특징

1. 음수 가중치가 존재하는 모든 정점에서의 최단 경로를 알 수 있음.

2. 시간복잡도 O(VE)

  정점이 V, 간선이 E라고 했을 때 V-1번 간선들을 모두 돌아봄.

3. 음의 가중치를 가지기 때문에, 음의 사이클을 조심해야함.

  ->V번째 간선들을 돌아봤을 때, 가중치가 수정이되면 음의 싸이클이 존재.

 

#다익스트라랑 vs 벨만포드

- 다익스트라

  시간 복잡도 O(V^2), 우선순위큐 사용시 O(ELogV)

  한 정점에서의 최단 경로를 가져옴.

 

- 벨만포드

  시간복잡도 O(VE)

 

-> 음의 가중치가 주어진 경우가 아니면, 우선순위큐를 이용한 다익스트라를 이용하자.

 

#소스

유의할 점은 

중복된 입력이 주어졌을때, 음의 사이클이라 생각하지 못하는 경우가 생김.

-> HashSet을 이용해 제거

https://meorimori.tistory.com/28?category=1092609 (HashSet에 클래스 중복 여부 판단)

package main.java.Temp;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

public class bac11657_타임머신_G4_벨만포드 {
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

	static int N;
	static int M;
	static ArrayList<Point> Arr;
	static int D[]; // 그정점까지의 최소거리

	static final int max = 1000000000;

	public static void main(String[] args) throws NumberFormatException, IOException {
		// 입력
		StringTokenizer st = new StringTokenizer(br.readLine());
		StringBuilder sb = new StringBuilder();
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		Set<Point> Hs = new HashSet();
		D = new int[N+1];

		//배열 입력
		for(int i =0; i<M; i++){
			st = new StringTokenizer(br.readLine());
			while(st.hasMoreTokens()) {
				int src = Integer.parseInt(st.nextToken());
				int dsc = Integer.parseInt(st.nextToken());
				int time = Integer.parseInt(st.nextToken());
				Hs.add(new Point(src,dsc,time));
			}
		}

		//중복제거후 리스트에 넣기
		Arr = new ArrayList(Hs);


		//정점 1부터 시작할것
		for(int i=2; i<=N; i++) D[i] = max;
		D[1] = 0;

		//N-1번 돌아야함, 마지막 번쨰는 음의싸이클 판단
		//그 이후로도 갱신시, 음의사이클
		for(int i=1; i<=(N-1); i++){
			for(int j=0; j<Arr.size(); j++){
				if(D[Arr.get(j).src] >= max) continue;
				if(D[Arr.get(j).dsc] > D[Arr.get(j).src] + Arr.get(j).time)
					D[Arr.get(j).dsc] = D[Arr.get(j).src] + Arr.get(j).time;
			}
		}

		boolean isCycle = false;
		for(int j=0; j<Arr.size(); j++){
			if(D[Arr.get(j).src] >= max ) continue;
			if(D[Arr.get(j).dsc] > D[Arr.get(j).src] + Arr.get(j).time)
				isCycle = true; // 더갱신됬으니.. 싸이클
		}

		//음이면
		//sb.append("");
		if (isCycle) {
			sb.append(-1);
		} else {
			for (int i = 2; i <= N; i++) {
				sb.append(D[i] == max ? -1 + "\n" : D[i] + "\n");
			}
		}

		System.out.print(sb);

	}

	public static class Point{
		int src;
		int dsc;
		int time;
		public Point(int src, int dsc, int time){
			this.src = src;
			this.dsc = dsc;
			this.time = time;
		}

		@Override
		public boolean equals(Object o) {
			if (this == o) return true;
			if (o == null || getClass() != o.getClass()) return false;
			Point point = (Point) o;
			return src == point.src &&
					dsc == point.dsc &&
					time == point.time;
		}

		@Override
		public int hashCode() {
			return (src+","+dsc+","+ time).hashCode();
		}
	}

}

 

 

 

 

'알고리즘' 카테고리의 다른 글

플로이드 와샬  (0) 2020.04.16
Prim 알고리즘  (0) 2020.04.09
알고리즘 - Next순열, 조합(2)  (0) 2020.03.11
22일차 - 알고(크루스칼,디익스트라,순열  (0) 2020.02.19
19일차 - 알고(그래프, disjoint, 최소신장)  (0) 2020.02.13