본문 바로가기
알고리즘 문제풀이/백준

[백준 1948] 임계경로

by m2162003 2021. 6. 19.

 

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

 

1948번: 임계경로

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

www.acmicpc.net

 

위상정렬 + 역추적 문제이다.

 

문제이해가 어려웠으나 요약하면

1. 시작점->목적지까지 도달하는데 가장 오래 걸리는 시간 구하기

2. 1만큼의 시간이 소요되는 경로에 속한 도로들의 수 구하기 이다. 

1분도 쉬지 않는다는 의미가 2라는 걸 이해하지 못했다...

 

1을 푸는 것은 위상정렬 + dp를 결합하면 어렵지 않게 해결할 수 있으나 문제는 2였다.

2에 대해 set으로 풀었으나 메모리 제한이 걸렸고 역추적이 필요함을 알게 되었다.

 

역추적을 어떻게 해야 하나 고민했는데 다른 사람들의 풀이를 참고한 결과 의외로 간단했다.

1에서 사용한 dp를 이용하여 진행한다.

이 때 주의할 점은 이미 방문한 노드에 대해서는 재확인하지 않는 다는 점이다.

visited를 체크하지 않았을 때 반례

in:

5

7

1 2 1

1 3 3

2 3 2

2 4 1

2 5 3

3 5 1

4 5 1

1 5

out:

4

5

while (!q.empty())
  {
    int top = q.front();
    q.pop();

    if (visited[top])
      continue;

    visited[top] = true;

    for (auto a : back[top])
    {
      if (dp[top] - dp[a.next] == a.cost)
      {
        q.push(a.next);
        roads++;
      }
    }
  }

 

정답코드는 다음과 같다.

#include <stdio.h>
#include <queue>
#include <vector>

using namespace std;
const int MAX = 10000 + 1;

int first, goal;
struct s
{
  int next, cost;
};

int indegree[MAX];
int dp[MAX]; //max cost 누적
bool visited[MAX];
vector<s> adj[MAX];
vector<s> back[MAX];
queue<int> q;

int main(void)
{
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 0; i < m; i++)
  {
    int from, to, cost;
    scanf("%d%d%d", &from, &to, &cost);
    adj[from].push_back({to, cost});
    back[to].push_back({from, cost}); //역추적을 위해 필요
    indegree[to]++;
  }

  scanf("%d%d", &first, &goal);
  q.push(first);

  while (!q.empty())
  {
    int top = q.front();
    q.pop();

    for (auto a : adj[top])
    {
      int next = a.next, cost = a.cost;
      indegree[next]--;

      if (dp[top] + cost > dp[next])
      {
        dp[next] = dp[top] + cost; //dp[i]는 ith 노드까지 max cost
      }

      if (indegree[next] == 0)
      {
        q.push(next);
      }
    }
  }

  int roads = 0;
  q.push(goal);

  while (!q.empty())
  {
    int top = q.front();
    q.pop();

    if (visited[top])
      continue;

    visited[top] = true;

    for (auto a : back[top])
    {
      if (dp[top] - dp[a.next] == a.cost)
      {
        q.push(a.next);
        roads++;
      }
    }
  }

  printf("%d\n%d\n", dp[goal], roads);
  return 0;
}

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 1806] 부분합  (0) 2021.06.20
[백준 1072] 게임  (0) 2021.06.20
[백준 11779] 최소비용 구하기 2  (0) 2021.04.11
[백준 11780]플로이드2  (0) 2021.04.11
[백준 20056] 마법사 상어와 파이어볼  (0) 2021.03.31

댓글