반응형
리뷰
https://www.acmicpc.net/problem/19238
처음 봤을 땐 긴가민가 했는데 N값이 작아 충분히 해결할 수 있을 것 같아 다익스트라로 풀이하였다.
전역 변수
- n : 맵의 한 변의 길이를 저장할 변수
- m : 손님의 수를 저장할 변수
- f : 남은 연료의 양을 저장할 변수
- sx, sy : 택시의 현재 위치를 저장할 변수
- dx, dy : 4방향 탐색을 위한 방향 배열
- dist : 각 좌표에서 다른 좌표로 이동하기 위한 최단거리를 저장할 정수형 2차 벡터의 2차 배열
- Pos : 최단 거리를 구하기 위한 구조체, x, y좌표와, d 거리, index 손님 번호를 의미한다, 거리 순으로 오름차순, 같다면 x순으로 오름차순, 같다면 y순으로 오름차순 정렬한다.
- Pos2 : 손님과 목표의 위치를 저장하기 위한 구조체, x, y좌표만 저장한다.
- start : 손님의 위치를 저장하기 위한 해시맵 key는 손님 번호, value는 Pos2타입의 좌표를 저장한다.
- dest : 손님의 도착지 위치를 저장하기 위한 해시맵 key는 손님 번호, value는 Pos2타입의 좌표를 저장한다.
함수
1. dijkstra
void dijkstra(int x, int y, vector<vector<int>>& temp)
각 좌표에서 다른 좌표로 이동하기 위한 최단 거리를 구하는 함수
- 매개변수로 시작 위치 좌표x, y와 현재 위치에서 갈 수 있는 최단 경로를 저장할 2차원 정수형 벡터 temp를 받는다.
- Pos 타입의 우선순위 큐 pq를 초기화 하고, 시작 위치 x, y와 시작 거리 0을 push한다.
- temp의 시작 위치 x, y는 0으로 초기화 한다.
- pq가 빌 때 까지 while루프를 수행하며, 각 루프마다 요소를 한개씩 꺼내어 준다.
- 요소의 위치로부터 4방향을 탐색하며 맵의 범위를 벗어나지 않고, 벽이 아니라면 이동을 진행해 준다.
- temp의 최소값을 갱신해 나가며 시작 위치로부터 모든 위치로의 최단 거리를 구해준다.
- temp를 참조형으로 전달하였기 때문에 따로 리턴할 필요는 없다.
문제풀이
- n, m, f값을 입력 받고, n * n크기의 맵의 정보를 입력받아 준다.
- 다시 n * n크기의 맵을 순회하며 각 좌표마다 최대 거리를 저장한 2차원 벡터 temp를 초기화 한다.
- 만약 맵 상에서 값이 0이라면 dijkstra함수에 i, j와 temp를 매개변수로 전달하여 호출한다.
- 갱신된 temp를 dist[i][j]의 값으로 저장해 준다.
- 택시의 초기위치를 sx, sy에 입력 받아준다.
- m개의 손님의 시작 위치와 목표 위치를 입력받는다.
- start, dest에 손님 번호를 key로, 시작 위치와 목표 위치의 x, y좌표를 value로 저장해 준다.
- dest가 빌 때 까지 while루프를 수행해 준다.
- Pos타입의 우선순위 큐 pq를 초기화 한다.
- start를 순회하며 모든 요소를 pq에 삽입해 준다. 이때의 인자는 x, y의 좌표와 dist[택시x][택시y][손님x][손님y]와 손님의 번호를 전달해 준다.
- pq의 top에 해당하는 거리만큼 f를 빼준다, 이후 만약 f가 0보다 작다면 break처리해 준다.
- 이제 택시 위치에서 목표 위치까지의 거리만큼 f를 빼준다, 이후 만약 f가 0보다 작다면 break처리해 준다.
- break문에 걸리지 않았다면 택시 위치에서 목표 위치까지의 거리의 2배만큼 f에 더해준다.
- 택시 위치를 목표위치로 갱신해 주고, start, dest에서 손님과 목표 위치를 제거해 준 뒤 pq에서 요소를 pop해준다.
- 모든 탐색을 완료하고 dest가 비었다면 f값을 출력한다, 만약 비지 않았다면 -1을 출력해 준다.
요약하자면 다음과 같다.
- 다익스트라를 통해 모든 좌표에서 다른 좌표까지의 이동 시 최단 거리를 dist로 저장한다.
- dist를 기반으로 현재 택시 위치와 가장 가까운 손님 거리를 구해 우선순위 큐로 가장 가까운 손님을 찾는다.
- 손님을 목표 위치까지 데려다 준 후 해당 택시의 위치에서 위 로직을 반복 수행한다.
트러블 슈팅
없음
참고 사항
- 거리의 값을 매우큰 값으로 설정하였으므로 손님을 태우거나 목표위치로 이동이 불가하다면 f는 0보다 작아진다.
- dest가 비지 않았다는 것은 모든 손님을 목표 지점까지 떨궈놓지 못했다는 말이다.
정답 코드
#include<iostream>
#include<queue>
#include<unordered_map>
using namespace std;
int n, m, f, sx, sy;
int lst[21][21];
int dx[] = { -1, 0, 0, 1 };
int dy[] = { 0, -1, 1, 0 };
vector<vector<int>> dist[21][21];
struct Pos {
int x, y, d, index;
bool operator<(const Pos& other) const {
if (d == other.d) {
if (x == other.x) return y > other.y;
return x > other.x;
}
return d > other.d;
}
};
struct Pos2 {
int x, y;
};
unordered_map<int, Pos2> start;
unordered_map<int, Pos2> dest;
void dijkstra(int x, int y, vector<vector<int>>& temp) {
priority_queue<Pos> pq;
pq.push({ x, y, 0 });
temp[x][y] = 0;
while (!pq.empty()) {
Pos pos = pq.top(); pq.pop();
int cx = pos.x, cy = pos.y, cd = pos.d;
if (temp[cx][cy] < cd) continue;
for (int i = 0; i < 4; ++i) {
int nx = cx + dx[i], ny = cy + dy[i], nd = cd + 1;
if (0 < nx && nx <= n && 0 < ny && ny <= n && !lst[nx][ny]) {
if (temp[nx][ny] > nd) {
temp[nx][ny] = nd;
pq.push({ nx, ny, nd });
}
}
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> f;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
cin >> lst[i][j];
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
vector<vector<int>> temp(n + 1, vector<int>(n + 1, 2e9));
if (!lst[i][j]) dijkstra(i, j, temp);
dist[i][j] = temp;
}
}
cin >> sx >> sy;
for (int i = 1; i <= m; ++i) {
int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
start[i] = { x1, y1 };
dest[i] = { x2, y2 };
}
while (!dest.empty()) {
priority_queue<Pos> pq;
for (auto i : start) {
pq.push({ i.second.x, i.second.y, dist[sx][sy][i.second.x][i.second.y], i.first });
}
Pos pos = pq.top();
f -= pos.d;
if (f < 0) break;
Pos2 pos2 = dest[pos.index];
f -= dist[pos.x][pos.y][pos2.x][pos2.y];
if (f < 0) break;
f += dist[pos.x][pos.y][pos2.x][pos2.y] * 2;
sx = pos2.x, sy = pos2.y;
start.erase(pos.index);
dest.erase(pos.index);
pq.pop();
}
if (dest.empty()) cout << f;
else cout << -1;
}
728x90
반응형
'알고리즘 공부 > C++' 카테고리의 다른 글
[G4] 백준 17141번 연구소 2 C++ 백트래킹, 너비 우선 탐색, 플러드필 (0) | 2025.01.07 |
---|---|
[G4] 백준 12869번 뮤탈리스크 C++ 너비 우선 탐색, 우선순위 큐 (0) | 2025.01.06 |
[G4] 백준 21939번 문제 추천 시스템 Version 1 C++ 우선순위 큐, 해시맵 (0) | 2025.01.04 |
[G2] 백준 13502번 단어퍼즐 2 C++ 트라이, 백트래킹, 런타임 전의 전처리 (2) | 2025.01.03 |
[D6] SWEA 1795번 인수의 생일 파티 C++ 다익스트라 (3) | 2025.01.03 |