[백준 19238번] 스타트 택시

2022. 9. 4. 16:22·알고리즘 문제풀이/백준
반응형

문제 링크: https://www.acmicpc.net/problem/19238

 

19238번: 스타트 택시

첫 줄에 N, M, 그리고 초기 연료의 양이 주어진다. (2 ≤ N ≤ 20, 1 ≤ M ≤ N2, 1 ≤ 초기 연료 ≤ 500,000) 연료는 무한히 많이 담을 수 있기 때문에, 초기 연료의 양을 넘어서 충전될 수도 있다. 다

www.acmicpc.net

<문제 풀이> 시뮬레이션, 우선순위 큐, BFS, 최단거리

먼저 택시를 기준으로 BFS를 사용해서 최단거리를 갱신합니다. 이때 다음 좌표로 이동할 때 택시의 연료가 부족하면 이동하면 안 됩니다. 현재 연료로 다음 좌표로 이동할 수 있으면 해당 손님의 좌표를 다음과 같은 기준으로 우선순위 큐에 기록합니다.

1. 현재 위치에서 최단거리가 가장 짧은 승객을 고른다.

2. 그런 승객이 여러 명이면 그중 행 번호가 가장 작은 승객을 고른다.

3. 그런 승객도 여러  명이면 그중 열 번호가 가장 작은 승객을 고른다.

아래 코드와 같이 우선순위 큐를 선언하면 우선순위 큐의 top에는 위 조건을 만족하는 손님이 존재하게 됩니다.

 

priority_queue<tuple<int, int, int>, vector<tuple<int, int, int> >, greater<tuple<int, int, int> > > pq;

 

BFS가 끝나면 우선순위 큐의 top에 존재하는 손님까지의 거리를 리턴하면 되고 만약 우선순위 큐가 비어있다면 연료가 부족해서 손님을 태우지 못한 경우이니 -1을 리턴하면 됩니다.

 

택시 BFS가 끝나면 이제 손님 BFS를 사용하면 됩니다.

 

손님 BFS에서 출발점과 도착점을 알고 있어야 하는데 단순히 2차원 배열에 손님의 도착 정보를 특정 값 형태로 저장하게 되면 안 됩니다.

 

왜냐하면 문제 조건에서 "모든 출발지는 서로 다르며, 각 손님의 출발지와 목적지는 다르다."라는 부분을 잘 이해하면 어떤 손님의 목적지가 어떤 손님의 출발지일 수도 있다는 걸 알 수 있습니다. 그래서 겹치는 부분을 처리하기 위해 해시맵을 이용해서 각 손님의 id와 목적지 좌표를 <key, value> 형태로 저장해야 합니다.

 

그리고 위 조건 때문에 택시가 목적지에 도착하자마자 바로 승객을 태울 수도 있기 때문에 이 부분도 예외처리를 해야 합니다.

 

<C++ 소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include<iostream>
#include<queue>
#include<tuple>
#include<functional>
#include<utility>
#include<algorithm>
#include<unordered_map>
using namespace std;
 
#define X first
#define Y second
 
int n, m, fuel;
int board[21][21];
int visited[21][21];
int tx, ty; //택시 위치
int dx[4] = { 0, 0, 1, -1 };
int dy[4] = { 1, -1, 0, 0 };
unordered_map<int, pair<int, int> > um; //각 손님의 도착 위치
priority_queue<tuple<int, int, int>, vector<tuple<int, int, int> >, greater<tuple<int, int, int> > > pq;
 
int taxiBFS() {
    fill(&visited[0][0], &visited[20][21], -1);
    queue<pair<int, int> > Q;
    Q.push({ tx, ty });
    visited[tx][ty] = 0;
    if (board[tx][ty] > 0)pq.push({ visited[tx][ty], tx, ty }); //손님을 바로 태우는 경우
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        for (int dir = 0; dir < 4; dir++) {
            int nx = cur.X + dx[dir];
            int ny = cur.Y + dy[dir];
            if (nx < 1 || ny < 1 || nx > n || ny > n)continue;
            if (visited[nx][ny] != -1 || board[nx][ny] == 1)continue; //이미 방문했거나 벽이면 무시
            if (visited[nx][ny] > fuel) continue; //다음 위치로 이동하는데 연료가 부족하면 무시
            visited[nx][ny] = visited[cur.X][cur.Y] + 1;
            if (board[nx][ny] > 0)pq.push({ visited[nx][ny], nx, ny }); // 다음 위치에 손님이 있는 경우
            Q.push({ nx, ny });
        }
    }
    if (pq.empty()) return -1; // 연료가 부족해서 손님을 못 태우는 경우
    else return get<0>(pq.top()); // 손님까지 거리를 리턴
}
 
int personBFS() {
    auto cur = pq.top(); pq.pop();
    pq = {};
    int d, x, y;
    tie(d, x, y) = cur;
    fill(&visited[0][0], &visited[20][21], -1);
    queue<pair<int, int> > Q;
    Q.push({ x, y });
    visited[x][y] = 0;
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        for (int dir = 0; dir < 4; dir++) {
            int nx = cur.X + dx[dir];
            int ny = cur.Y + dy[dir];
            if (nx < 1 || ny <1 || nx > n || ny > n)continue;
            if (visited[nx][ny] != -1 || board[nx][ny] == 1)continue;
            visited[nx][ny] = visited[cur.X][cur.Y] + 1;
            Q.push({ nx, ny });
            if (nx == um[board[x][y]].X && ny == um[board[x][y]].Y) {//목적지에 도착
                tx = nx;
                ty = ny;//택시 위치 목적지로 갱신
                board[x][y] = 0; //해당 승객 처리
                if (visited[nx][ny] > fuel) return -1; //만약 연료가 부족하면 실패
                return visited[nx][ny]; //return 소비한 연료
            }
        }
    }
    if (board[x][y]) return -1; // 목적지에 도착하지 못하면 승객을 처리하지 못함 -> return -1
}
 
void solution() {
    int cnt = 0;
    while (cnt < m) { //승객을 모두 처리할 때까지
        int consumeTaxi = taxiBFS();
        if (consumeTaxi == -1) {
            fuel = -1;
            return;
        }
        fuel -= consumeTaxi; //승객이 있는 곳까지 연료 감소
        int consumePerson = personBFS();
        if (consumePerson == -1) {
            fuel = -1;
            return;
        }
        fuel += consumePerson; // 목적지까지 연료 감소 후 소모한 연료 양 두 배 충전
        cnt++;
    }
    
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
     
    cin >> n >> m >> fuel;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> board[i][j];
        }
    }
    cin >> tx >> ty;
    for (int i = 0; i < m; i++) {
        int sx, sy, ex, ey;
        cin >> sx >> sy >> ex >> ey;
        board[sx][sy] = i + 2; // 각 손님의 시작 위치 => 손님은 2이상의 key값으로 구분
        um[i + 2] = { ex, ey }; // 각 손님 식별 key는 2이상의 수
    }
    solution();
    cout << fuel;
    return 0;
}
Colored by Color Scripter
cs

 

반응형
저작자표시 (새창열림)

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

[백준 1083번] 소트  (0) 2023.02.26
[백준 1071번] 소트  (0) 2023.02.25
[백준 17141번] 연구소 2  (0) 2022.08.04
[백준 17144번] 미세먼지 안녕!  (0) 2022.08.03
[백준 1026번] 보물  (0) 2022.08.01
'알고리즘 문제풀이/백준' 카테고리의 다른 글
  • [백준 1083번] 소트
  • [백준 1071번] 소트
  • [백준 17141번] 연구소 2
  • [백준 17144번] 미세먼지 안녕!
슥지니
슥지니
개발 블로그
  • 슥지니
    슥지니의 코딩노트
    슥지니
  • 전체
    오늘
    어제
    • 분류 전체보기 (199)
      • 알고리즘 문제풀이 (158)
        • 백준 (158)
      • 알고리즘 (6)
      • Node.js (2)
        • MongoDB (1)
        • 기타 (1)
      • spring (0)
      • 가상화폐 (1)
        • 바이낸스(Binance) (1)
      • C++ 테트리스 게임 (1)
      • C++ (10)
      • 안드로이드 프로그래밍 (21)
        • 코틀린 (21)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준
    콘솔 테트리스 게임
    dfs
    그리디
    BFS
    코틀린을 활용한 안드로이드 프로그래밍
    백트랙킹
    dp
    코틀린
    다이나믹 프로그래밍
    우선순위 큐
    C
    그래프
    C++
    Kotlin
    자료구조
    알고리즘
    구현
    콘솔
    시뮬레이션
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
슥지니
[백준 19238번] 스타트 택시
상단으로

티스토리툴바