[백준] 1948. 임계경로

2023. 11. 14. 03:32

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

 

1948번: 임계경로

첫째 줄에 도시의 개수 n(1 ≤ n ≤ 10,000)이 주어지고 둘째 줄에는 도로의 개수 m(1 ≤ m ≤ 100,000)이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 도로의 정보가 주어진다. 처음에는 도로의

www.acmicpc.net

 

## 접근법

출발지점에서 도착지점까지 오래 걸리는 시간과 해당 경로의 개수를 구해야 한다. 

 

출발지점에서 도착지점까지 오래 걸리는 시간을 구하기 위해 나는 아래와 같은 일차원 배열을 선언했다.

dist[노드번호] = 노드번호까지 가는데 걸리는 최대시간

그리고 경로를 추적해야하기 때문에 일차원 벡터 배열을 선언했다.

vector<int> prv[노드번호] = 노드번호로 in-degree한 노드번호들의 벡터

 

전략은 다음과 같다.

1) bfs로 모든 경로를 탐색한다.

2) 노드(a)로 in-degree하는 상황을 가정한다.

  - 만약 dist[a]보다 오래 걸리는 경로라면 dist[a]를 해당시간으로 초기화한다. 그리고 a로 들어오는 노드를 prv[a]에 추가한다.

  - 만약 dist[a]만큼 걸린다면, a로 들어오는 노드를 prv[a]에 추가한다

  - 만약 dist[a]보다 짧게 걸린다면 in-degree하지 않는다. 

3) dfs로 도착 노드로 들어왔던 경로를 탐색하여 경로의 개수를 구한다.

 

코드로 보기

```cpp

#include <bits/stdc++.h>
using namespace std;
#define init cin.tie(0)->sync_with_stdio(0)
#define ii pair<int, int>

int n, m;
int dist[10005];
vector<ii> adj[10005];
vector<int> prv[10005];
bool visited[10005];


int st, en;
void bfs() {
  queue<ii> q;
  q.push({st, 0});

  while(q.size()) {
    auto [cur, distance] = q.front();
    q.pop();

    for(auto [nxt, cost]: adj[cur]) {

      if(dist[nxt] < distance + cost) {
        dist[nxt] = distance + cost;
        prv[nxt].clear();
        prv[nxt].push_back(cur);
        q.push({nxt, distance + cost});
      }
      else if(dist[nxt] == distance + cost) {
        prv[nxt].push_back(cur);
      }

    }
  }
}
int cnt;
bool firstwhere = false;

void dfs(int cur) {
  if(visited[cur]) return;
  if(cur == st) return; 

  visited[cur] = true;
  cnt += prv[cur].size();

  for(auto x: prv[cur]) {
    dfs(x);
  }
}

int main() {
  init;
  cin >> n >> m;
  for(int i=0; i<m; i++){
    int a, b, c;
    cin >> a >> b >> c;
    adj[a].push_back({b, c});
  }
  cin >> st >> en;
  bfs();
  dfs(en);
  // for(auto x: prv[6]) { cout << x << ' '; }

  cout << dist[en] << '\n';
  cout << cnt;
}

```