정리충의 정리노트

[백준] 5719: 거의 최단 경로 (수정) 본문

PS/ShortestPath

[백준] 5719: 거의 최단 경로 (수정)

ioqoo 2020. 2. 21. 22:15

0. 문제 주소

 

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

 

5719번: 거의 최단 경로

문제 요즘 많은 자동차에서는 GPS 네비게이션 장비가 설치되어 있다. 네비게이션은 사용자가 입력한 출발점과 도착점 사이의 최단 경로를 검색해 준다. 하지만, 교통 상황을 고려하지 않고 최단 경로를 검색하는 경우에는 극심한 교통 정체를 경험할 수 있다. 상근이는 오직 자기 자신만 사용 가능한 네비게이션을 만들고 있다. 이 네비게이션은 절대로 최단 경로를 찾아주지 않는다. 항상 거의 최단 경로를 찾아준다. 거의 최단 경로란 최단 경로에 포함되지 않는 도로로만

www.acmicpc.net

 

 

1. 풀이

 

최단 경로가 여러개일 수 있고, 그 여러 최단 경로끼리도 간선을 공유할 수 있다.

 

풀이는 다음과 같다.

 

 

0. 문제에서 주어지는 방향 간선으로 그래프를 만들고, 그 역방향 간선으로 별도의 그래프를 만들어 둔다.

 

1. 다익스트라 알고리즘을 적용한다.

 

2. 도착점에서부터 역방향 간선으로 만든 그래프를 순회하며, 현재의 노드를 curr, 다음 노드를 next, 가중치를 weight이라고 하면, dist[curr] - weight = dist[next]를 만족하는 경우 (next, curr) 간선은 최단 경로에 포함되는 간선이다. 

역방향으로 BFS 순회를 할 때 이미 최단 경로에 포함되었다고 확인했던 간선이면 continue 해주어야 한다. (Line 85) 재채점돼서 MLE 떴다가 다시 AC 띄우는데 고생함 ㅠ

 

3. 이를 avail 배열에 저장한다. ( avail[i][j] = (i, j) 간선이 최단 경로에 포함되는 경우 true)

 

4. 다시 한번 다익스트라를 적용하되 최단 경로에 포함된 경우 그 간선은 이용하지 않는다.

 

 

 

2. 풀이 코드

 

* 유의할 점

 

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>

#define pii pair<int, int>
#define MAX 503
#define INF 987654321

using namespace std;

int N, M, S, D;
int dist[MAX];
bool available[MAX][MAX]; // available[i][j] = i -> j로 가는 간선은 최단 경로에 포함됨. 
bool visited[MAX];
vector<pii> graph[MAX];
vector<pii> rev_graph[MAX];

int main(){
	#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
	#endif
	
	while(1){
		
		scanf("%d %d", &N, &M);
		if (N==0 && M==0) break;
		
		for (int i=0;i<N;i++){
			dist[i] = INF;
		}
		memset(visited, 0, sizeof(visited));
		memset(available, 0, sizeof(available));
		
		for (int i=0;i<N;i++){
			graph[i].clear();
			rev_graph[i].clear();
		}
		priority_queue<pii, vector<pii>, greater<pii>> PQ;
		
		
		scanf("%d %d", &S, &D);
		
		
		for (int i=0;i<M;i++){
			int u, v, w;
			scanf("%d %d %d", &u, &v, &w);
			graph[u].push_back(pii(v, w));
			rev_graph[v].push_back(pii(u, w));
		}
		
		dist[S] = 0;
		PQ.push(pii(0, S));
		
		while(!PQ.empty()){
			auto p = PQ.top();
			PQ.pop();
			int curr = p.second, curr_dist = p.first;
            if (dist[curr] < curr_dist) continue;
			// visited[curr] = true;
			for (auto pp: graph[curr]){
				int next = pp.first, weight = pp.second;
				if (dist[next] > curr_dist + weight){
					dist[next] = curr_dist + weight;
					PQ.push(pii(dist[next], next));
				}
			}
		}
		if (dist[D] == INF) {
			printf("-1\n");
			continue;
		}
		
		queue<pii> Q;
		Q.push(pii(D, dist[D]));
		while(!Q.empty()){
			auto pp = Q.front();
			int curr = pp.first, curr_remain = pp.second;
			Q.pop();
            if (curr == S) continue;            
			for (auto ppp: rev_graph[curr]){
				int next = ppp.first, weight = ppp.second;
                if (available[next][curr]) continue;
				if (curr_remain - weight == dist[next]){
					available[next][curr] = true;
					Q.push(pii(next, dist[next]));
				}
			}
		}
		
//		for (int i=0;i<N;i++){
//			for (int j=0;j<N;j++){
//				printf("%d ", available[i][j]);
//			}
//			printf("\n");
//		}
//		printf("\n");
		
		for (int i=0;i<N;i++){
			dist[i] = INF;
		}
		// memset(visited, 0, sizeof(visited));
		
		dist[S] = 0;
		PQ.push(pii(0, S));
		while(!PQ.empty()){
			auto p = PQ.top();
			PQ.pop();
			int curr = p.second, curr_dist = p.first;
            if (dist[curr] < curr_dist) continue;
			// visited[curr] = true;
			for (auto pp: graph[curr]){
				int next = pp.first, weight = pp.second;
				if (!available[curr][next] && dist[next] > curr_dist + weight){
					dist[next] = curr_dist + weight;
					PQ.push(pii(dist[next], next));
				}
			}
		}
		if (dist[D] == INF) printf("-1\n");
		else printf("%d\n", dist[D]);
		
	} 
	
	return 0;
} 

 

 

 

'PS > ShortestPath' 카테고리의 다른 글

[백준] 9323: 무임승차  (0) 2020.03.10
[백준] 2982: 국왕의 방문  (0) 2020.03.07
[백준] 2211: 네트워크 복구  (0) 2020.03.07
[백준] 9370: 미확인 도착지  (0) 2020.03.07
[백준] 3860: 할로윈 묘지  (0) 2020.02.21
Comments