경로나 값을 저장해서 다음에 그 값을 참조해야 하는 경우의 문제들을 정리해보자.
대부분 그래프 탐색이나 BFS, DFS 문제에서 경로 찾기, 걸린 시간 등 출발지에서의 값을 가지고 있어야 하는 경우가 많다.
1697 문제
아이디어: BFS
현재 값인 N에서 가능한 동작은 3가지이다. +1, -1, 2배 이다. 이 경우로 탐색 가능한 값에 대해서 (현재 값까지 걸린 시간 + 1)을 더해서 저장해두고 이에 대해서 다시 탐색을 도는 방식으로 문제를 해결할 수 있다.
이때 저장해두는 값은 시작 노드인 N에서부터 걸린 시간이 된다.
구현
// 1697 숨바꼭질
#include <iostream>
#include <queue>
using namespace std;
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int N, K;
cin>>N>>K;
// 값 저장을 위한 1차원 배열 -> 초기화 필수
int d[100001] = {0,};
// BFS 시작
queue<int> q;
q.push(N);
d[N] = 1;
while(!q.empty())
{
int temp = q.front();
q.pop();
// 목표 지점이면 출력하고 종료
if (temp == K)
{
cout<<d[temp] - 1<<"\n";
return 0;
}
// -1에 대한 동작: 방문하지 않았고 범위 내에 있다면
if (temp - 1 >= 0 && d[temp - 1] == 0)
{
d[temp - 1] = d[temp] + 1;
q.push(temp - 1);
}
// +1에 대한 동작: 방문하지 않았고 범위 내에 있다면
if (temp + 1 <= 100000 && d[temp + 1] == 0)
{
d[temp + 1] = d[temp] + 1;
q.push(temp + 1);
}
// 2배에 대한 동작: 방문하지 않았고 범위 내에 있다면
if (temp * 2 <= 100000 && d[temp * 2] == 0)
{
d[temp * 2] = d[temp] + 1;
q.push(temp * 2);
}
}
return 0;
}
11779 문제
아이디어: 다익스트라
노드에서 다른 노드까지의 최단 경로를 찾는 문제이므로 다익스트라 알고리즘을 사용하여 풀 수 있다.
이때 중요한 점은그 경로를 저장하는 것이다. 이는 어떻게 해결할 수 있을까?
먼저 다익스트라 알고리즘은 Greedy 알고리즘이다. 즉 모든 경로까지의 최단 경로를 모두 확인하고 최단인 경우에 대해서 그 노드까지의 거리 값을 업데이트 하는 것이기 때문에, queue에서 빼거나 dist 거리 값을 업데이트할 때 확인한 노드를 저장하는 방식으로 문제를 풀게 되면 최단 경로에 포함되지 않은 노드도 저장하게 된다. 또한 같은 노드가 중복으로 저장될 가능성도 있다.
따라서 특정 노드를 방문할 때마다 이 노드의 부모 노드의 값을 저장하는 방식으로 문제를 풀어야 한다. 마지막에는 목적지 노드의 부모 노드를 타고 올라가다 더 이상 부모 노드가 없는 경우 시작 경로에 도달했음을 알 수 있다.
따라서 부모 노드 저장을 위한 1차원 배열을 선언하고 0으로 초기화한다.
마지막에 저장된 부모 노드가 0이 아닌 경우 경로가 존재한다는 것이고, 0이 된 경우 시작 경로에 도달했다는 뜻이 된다.
구현
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
vector<pair<int, int>> graph[1001];
// 부모 노드 저장 용도
int route[1001];
int dist[1001];
void dijkstra(int start)
{
priority_queue<pair<int, int>> pq;
// {가중치, 노드}
pq.push({0, start});
dist[start] = 0;
while (!pq.empty())
{
int w = pq.top().first * -1;
int now = pq.top().second;
pq.pop();
if (dist[now] < w)
continue;
for(int i = 0;i < graph[now].size();i++)
{
int cost = w + graph[now][i].second;
if (cost < dist[graph[now][i].first])
{
// 경로 저장을 위해 배열에 현재 노드를 넣어서 부모노드를 체크함
route[graph[now][i].first] = now;
dist[graph[now][i].first] = cost;
pq.push({cost * -1, graph[now][i].first});
}
}
}
}
int main()
{
// N(node), M(edge)
int N, M;
cin>>N>>M;
for(int i = 0;i < M;i++)
{
int a, b, c;
cin>>a>>b>>c;
// {노드, 가중치}
graph[a].push_back({b, c});
}
int start, target;
cin>>start>>target;
fill_n(dist, N + 1, 1e9);
fill_n(route, 1001, 0);
dijkstra(start);
cout<<dist[target]<<"\n";
stack<int> st;
st.push(target);
while(1)
{
target = route[target];
if (target == 0)
break;
st.push(target);
}
cout<<st.size()<<"\n";
while(!st.empty())
{
cout<<st.top()<<" ";
st.pop();
}
return 0;
}
'ALGORITHM > c&c++ baekjoon' 카테고리의 다른 글
DP + LCS Algorithm에 대한 이해: 최장 공통 부분 수열 (Longest common subsequence problem) (0) | 2022.06.14 |
---|---|
음수 간선을 가지는 그래프의 최단 경로: 벨만-포드 알고리즘 (0) | 2022.05.20 |
[C++/3665] 최종 순위 - using 위상 정렬 (topology sort) (0) | 2022.05.14 |
[C++/7576] 토마토 - using BFS (0) | 2022.05.11 |
[C++/2887] 행성 터널 - using MST : Kruskal Algorithm (0) | 2022.05.11 |