피너클의 it공부방
백준 5710 거의 최단 경로 (c++) : 피너클 본문
https://www.acmicpc.net/problem/5719
다익스트라 문제다.
다익스트라로 최단 경로를 구하며 vector<int>parent에 지금 정점 이전 정점들을 집어넣고
parent에서 구해진 정점들 간의 연결을 전부 끊어준다음
다시 다익스트라를 돌릴것이다.
long long n, m, s, d;
vector<pair<long long, long long>> graph[501];
long long dist[501];
long long visited[501][501];
vector<int> parent[501];
사용하는 변수들이다.
while (true) {
cin >> n >> m;
if (n == 0 && m == 0) break;
for (int i = 0; i < 501; i++) {
for (int j = 0; j < 501; j++) {
visited[i][j] = false;
}
graph[i].clear();
parent[i].clear();
}
cin >> s >> d;
for (int i = 0; i < m; i++) {
long long u, v, p;
cin >> u >> v >> p;
graph[u].push_back({ v, p });
visited[u][v] = true;
}
입력 부분이다.
visited, graph, parent 전부 초기화 해주는거 잊으면 안된다. 나는 parent 초기화 하는거 잊어서 많이 틀렸다.
visited는 내가 변수 명을 잘못 썻는데 그래프라 생각하면 된다.
visited[5][10] = true면 5에서 10으로 갈 수 있다는 것이다.
for (int i = 0; i < n; i++) dist[i] = 987654321;
dijkstra(s);
for (int i = 0; i < n; i++) dist[i] = 987654321;
remove_dijkstra(d);
for (int i = 0; i < n; i++) dist[i] = 987654321;
dijkstra(s);
그 후에는 다익스트라 돌리고
다익스트라 돌린걸로 지워준다음에
다시 다익스트라 돌리면 된다.
void dijkstra(long long start) {
dist[start] = 0;
priority_queue<pair<long long, long long>> pq;
pq.push({ 0, start });
while (!pq.empty()) {
long long now = pq.top().second;
long long now_distance = -pq.top().first;
pq.pop();
if (dist[now] < now_distance) continue;
for (long long i = 0; i < graph[now].size(); i++) {
long long next = graph[now][i].first;
long long next_distance = graph[now][i].second;
if (!visited[now][next]) continue;
if (now_distance + next_distance == dist[next]) {
parent[next].push_back(now);
}
else if (now_distance + next_distance < dist[next]) {
parent[next].clear();
parent[next].push_back(now);
dist[next] = now_distance + next_distance;
pq.push({ -dist[next], next });
}
}
}
}
다익스트라다.
전부 기본 다익스트라랑 같지만
if (now_distance + next_distance == dist[next]) {
parent[next].push_back(now);
}
else if (now_distance + next_distance < dist[next]) {
parent[next].clear();
parent[next].push_back(now);
dist[next] = now_distance + next_distance;
pq.push({ -dist[next], next });
}
이것들을 추가해줘야한다.
현재 정점에서 다음 정점으로 가는 비용이 기존에 비용과 같으면
parent[next]에 현재 정점을 넣어준다.
이렇게 하면 parent[next]안에는 next이전의 정점들이 모이게 된다.
만약 지금 비용이 기존 비용보다 더 싸다면
parent[next]를 초기화하고 넣어주면 된다.
for (long long i = 0; i < graph[now].size(); i++) {
long long next = graph[now][i].first;
long long next_distance = graph[now][i].second;
if (!visited[now][next]) continue;
visited는 아까도 말했지만 갈수있는지이다. now에서 next로 못가면 그냥 지나간다.
void remove_dijkstra(int end) {
queue<int> q;
q.push(end);
bool vvisited[501] = { false, };
vvisited[end] = true;
while (!q.empty()) {
int now = q.front();
q.pop();
for (int i = 0; i < parent[now].size(); i++){
int next = parent[now][i];
visited[next][now] = false;
if (!vvisited[next]) {
vvisited[next] = true;
q.push(next);
}
}
}
}
visited를 제거하는 함수이다.
parent에는 해당 정점 이전의 정점들이 모여있다.
즉 now는 지금의 정점이고 next는 이전의 정점들이다.
next -> now로 이동한다.
그러니 visited[next][now]를 false로 해준다.
그 뒤로는 bfs와 같다.
for (int i = 0; i < n; i++) dist[i] = 987654321;
dijkstra(s);
for (int i = 0; i < n; i++) dist[i] = 987654321;
remove_dijkstra(d);
for (int i = 0; i < n; i++) dist[i] = 987654321;
dijkstra(s);
이렇게 remove까지 하고 다익스트라를 한번 더 돌려준뒤
if (dist[d] == 987654321) cout << -1 << '\n';
else cout << dist[d] << '\n';
}
dist가 987654321이라면 도달하지 못했다는 것이다. -1을 출력한다.
아니면 바로 출력한다.
'백준' 카테고리의 다른 글
백준 13511 트리와 쿼리 2 (c++) : 피너클 (1) | 2025.09.01 |
---|---|
백준 14868 문명 (c++) : 피너클 (0) | 2025.08.30 |
백준 11378 열혈강호 4 (c++) : 피너클 (2) | 2025.08.23 |
백준 1214 쿨한 물건 구매 (c++) : 피너클 (2) | 2025.08.22 |
백준 11585 속타는 저녁 메뉴 (c++) : 피너클 (0) | 2025.08.21 |