카테고리 없음
[GOLD3] ACM Craft
부레두
2024. 6. 3. 21:23
1. 문제 링크
https://www.acmicpc.net/problem/1005
2. 문제 이해 및 풀이 전략
위상 정렬 숙달을 위해 풀어본 첫 번째 문제.
처음 풀어본 줄 다리기 문제의 풀이법에 더해 '건설 시간'이라는 조건이 하나 더 붙었다.
조건의 추가와는 별개로 풀이의 핵심을 생각해보자면 다음 단계에 해당하는 노드로 진행하기 위해서는 같은 건설 단계의 노드 중 가장 긴 건설시간을 쓰는 노드의 시간이 그 단계의 소요 시간이 된다는 말이다.
그렇게 각 단계의 소요 건설 시간을 계산해본다.
* 2차 시도
각 단계의 시간을 계산하는 도중 건설 목표에 도달한 후 최소 시간을 저장하지 않고 지금까지 거친 시간을 출력하는 점을 개선해야했다.
메모이제이션을 사용해 각 지점에서 최소 시간을 저장하고, 단계를 넘기면 최장 시간을 넘긴다.
3. 풀이 코드
int T;
int N, K;
int W;
int main()
{
fastio;
cin >> T;
while (T--)
{
cin >> N >> K;
vector<int> Time; // 건설 시간
vector<int> Degree(N + 1, 0); // 차수 백터
vector<vector<int>> Building(N + 1); // 건물 그래프
vector<int> Result(N + 1, 0); // 최소 시간 저장 메모이제이션
// 건설 시간 입력
Time.push_back(0); // 번호 맞추기
for (int i = 1; i <= N; i++)
{
int value;
cin >> value;
Time.push_back(value);
}
// 건물 그래프, 차수 입력
for (int i = 0; i < K; i++)
{
int X, Y;
cin >> X >> Y;
Building[X].push_back(Y);
Degree[Y]++;
}
// 최종 목적지 건물 입력
cin >> W;
// 위상 정렬 시작
queue<int> q;
// 진입 차수가 0인 노드를 큐에 삽입
for (int i = 1; i <= N; i++)
{
if (Degree[i] == 0)
{
q.push(i);
Result[i] = Time[i]; // 초기 건물 시간 저장
}
}
while (!q.empty())
{
int current = q.front();
q.pop();
for (int i = 0; i < Building[current].size(); i++)
{
int next = Building[current][i];
Result[next] = max(Result[next], Result[current] + Time[next]); // 최소 시간 갱신
Degree[next]--;
if (Degree[next] == 0)
q.push(next);
}
}
cout << Result[W] << '\n';
}
return 0;
}
4. 결과 및 회고
알고리즘의 적당한 예시로 보여줄만한 문제가 끝나면 어김없이 등장하는 다른 알고리즘과 함께 사용해야 하는 문제...라고 생각했다. 사실 각 노드의 최소시간을 저장해 놓는다는 생각이 나온 것은 문제를 잡고 꽤 오랜시간이 지난 후.