어흥

[백준 1948] 임계경로 (C++) 본문

알고리즘/백준

[백준 1948] 임계경로 (C++)

라이언납시오 2020. 3. 13. 00:09
728x90
반응형

문제 링크: https://www.acmicpc.net/problem/1948

 

1948번: 임계경로

첫째 줄에 도시의 개수 n(1 ≤ n ≤ 10,000)이 주어지고 둘째 줄에는 도로의 개수 m(1 ≤ m ≤ 100,000)이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 도로의 정보가 주어진다. 처음에는 도로의 출발 도시의 번호가 주어지고 그 다음에는 도착 도시의 번호, 그리고 마지막에는 이 도로를 지나는데 걸리는 시간이 주어진다. 도로를 지나가는 시간은 10,000보다 작거나 같은 자연수이다. 그리고 m+3째 줄에는 지도를 그리는 사람들이

www.acmicpc.net

1. 주의할 점

- 위상정렬 혹은 다익스트라로 풀 수있는 문제지만 나는 다익스트라로 해결했다.

- 우선, 다익스트라를 지금까지 완전히 잘못 사용하고 있었다.

if (dist[cidx] > cv) continue;
/*if (visit[cidx]) continue;
visit[cidx] = true;*/

주석처럼 사용할 경우 최장경로를 제대로 갱신할 수 없다. 짧은 길이 여러개로 이뤄져서 한참으로 돌아오고 있는 총 누적거리가 긴 경로는 짧은 길로 이미 해당 Node를 방문해서 다음 경로를 진행하고 있다면 최장거리는 갱신되지 않는다.

쉽게 설명하기 위해 밑의 그림을 첨부한다(빨간 숫자: 가중치, 파란 숫자: Node)

- 경로를 기억하는 과정이 여러가지 존재하지만 상당히 까다롭다.

 

2. 구현

- 입력을 받을 때, 정방향과 더불어 역방향의 그래프를 저장한다(역방향의 경우 도착지점 -> 시작지점을 알아내기 위해)

- 다익스트라를 통해서 시작지점 -> 도착지점까지의 최장거리를 구한다. + Dist배열에 시작지점 -> 다른 모든 Node까지의 거리를 구해놓는다.

- 도착지점을 -> 시작지점을 통해 경로를 구한다. 구하는 방법은 다음과 같다.

  도착지점에서 이동할 수 있는 Node로 간선의 가중치 만큼 이동했을 때, 이동한 Node의 Dist[Node] +가중치 = Dist[도착지점] 이면 Result++하고, 해당 Node에 처음 방문했다면 Queue에 저장해서 시작지점에 도착할 때까지 이어나간다.

 

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
struct info {
	int idx, val, cnt;
};
struct cmp {
	bool operator()(info &a, info &b) {
		return a.val < b.val;
	}
};
info tmp;
vector<info> v[10001];		//정방향 도로
vector<info> rev[10001];	//역방향 도로
long long dist[10001];
bool visit[10001] = { false, };

int main() {
	ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
	int node, edge, s, e, val, result = 0, start, target;
	cin >> node >> edge;
	for (int i = 0; i < edge; i++) {
		cin >> s >> e >> val;
		tmp.idx = e;
		tmp.val = val;
		v[s].push_back(tmp);
		tmp.idx = s;
		rev[e].push_back(tmp);
	}
	for (int i = 1; i <= node; i++)
		dist[i] = -1;
	cin >> start >> target;
	priority_queue<info,vector<info>,cmp> pq;
	tmp.idx = start;
	tmp.val = 0;
	dist[start] = 0;
	pq.push(tmp);
	//최장거리 다익스트라
	while (!pq.empty()) {
		int cidx = pq.top().idx;
		int cv = pq.top().val;
		pq.pop();
		if (dist[cidx] > cv) continue;
		/*if (visit[cidx]) continue;
		visit[cidx] = true;*/
		for (int i = 0; i < v[cidx].size(); i++) {
			int next = v[cidx][i].idx;
			int nv = v[cidx][i].val;
			if (dist[next] < cv + nv) {
				dist[next] = cv + nv;
				tmp.idx = next;
				tmp.val = cv + nv;
				pq.push(tmp);
			}
		}
	}
	//역방향도로 시작
	for (int i = 1; i <= node; i++) {
		cout << dist[i] << " ";
		visit[i] = false;
	}
	system("pause");
	queue<int> q;
	q.push(target);
	visit[target] = true;
	while (!q.empty()) {
		int cidx = q.front();
		q.pop();	
		for (int i = 0; i < rev[cidx].size(); i++) {
			int next = rev[cidx][i].idx;
			int nv = rev[cidx][i].val;
			if (dist[next] + nv == dist[cidx]) {
				result++;
				if (!visit[next]) {
					q.push(next);
					visit[next] = true;
				}
			}
		}
	}
	cout << dist[target] << '\n' << result;
	system("pause");
	return 0;
}
728x90
반응형

'알고리즘 > 백준' 카테고리의 다른 글

[백준 13459] 구슬 탈출 (C++)  (0) 2020.03.13
[백준 15685] 드래곤 커브 (C++)  (0) 2020.03.13
[백준 2623] 음악프로그램 (C++)  (0) 2020.03.12
[백준 6118] 숨바꼭질 (C++)  (0) 2020.03.12
[백준 16179] 두 동전 (C++)  (0) 2020.03.11
Comments