halang-log
💡 PS

[BOJ] 1948 임계경로

date
May 13, 2022
slug
boj-1948
author
status
Public
tags
PS
summary
임계경로 문제에 대한 풀이입니다.
type
Post
thumbnail
category
💡 PS
updatedAt
Aug 3, 2023 09:26 AM
언어

문제

풀이

만나는 시간을 구하는 방법은 BOJ 2611 자동차 경주와 같다.
이 문제에서 추가로 생각해봐야 하는 것은 해당 경로가 유일하지 않을 수 있다는 것이다.
나는 자동차 경주 문제를 풀고 이 문제를 풀었어서 비슷한 로직으로 생각을 했다.
다만 추가로 고려해 준 것은 문제 조건을 만족하는 경로가 여러개 일 수도 있다는 것!
따라서 나는 ans(ans[i] = i노드 전에 최대 비용으로 방문한 노드)를 단순히 배열이 아닌 벡터로 선언했다.
참고로 cost[i]는 i노드 까지 가는데 드는 최대 비용을 의미한다.
문제 풀이를 간단히 해보자면, st는 시작점이고 en은 도착점이다.
우선 벡터v에 도로 정보를 저장한다. 그리고 진입차수를 나타내주는 배열인 inDegree도 바로 반영해준다.
go는 topological sort를 해주는 코드이다. 시작점 st를 먼저 큐에 넣어준다.
사이클은 없으므로 n번 반복해주는 반복문 안에서 가장 먼저 들어온 노드를 t에 저장하고 pop한다.
노드t에서 다음으로 갈 노드들 j를 반복문을 통해 확인해준다.
만약 cost[도착노드]가 cost[출발노드]+비용(시간) 보다 작다면 ans[도착노드]를 비워주고 ans[도착노드]에 새 노드 t를 넣어준다.
두 값이 같다면 그냥 ans[도착노드]에 새 노드 t를 넣어준다.(같은 비용을 가진 경로가 여러개인 경우다.)
cost[도착노드]에 값을 갱신시켜주고 진입차수가 0이라면 큐에 push 해준다.
그 다음 chk에서 재귀함수를 이용하여 비용이 최대인 경로 상에 있는 모든 간선의 수(toatal)를 구해주었다.
중복 계산을 막기 위해 해당 노드 방문 여부인 vis배열로 체크해 주었다.

코드

#include <cstdio> #include <algorithm> #include <queue> using namespace std; struct info { int e, cost; }; int n, m, st, en, total = 0; int inDegree[10000]; int cost[10000]; vector<int> ans[10000]; int vis[10000]; vector<info> v[10000]; void go() { queue<int> q; q.push(st); for(int i = 0; i < n; i++) { int t = q.front(); q.pop(); for(auto j : v[t]) { if (cost[j.e] < cost[t] + j.cost) { ans[j.e].clear(); ans[j.e].push_back(t); } else if (cost[j.e] == cost[t] + j.cost) ans[j.e].push_back(t); cost[j.e] = max(cost[j.e], cost[t] + j.cost); if (--inDegree[j.e] == 0) q.push(j.e); } } } void chk(int t) { if (vis[t]) return; vis[t] = 1; for(int i : ans[t]) { total++; chk(i); } } int main() { scanf("%d %d", &n, &m); for(int a, b, c, i = 0; i < m; i++) { scanf("%d %d %d", &a, &b, &c); a--; b--; v[a].push_back({b,c}); inDegree[b]++; } scanf("%d %d", &st, &en); st--; en--; go(); chk(en); printf("%d\n%d", cost[en], total); }