ABOUT ME

알고리즘 문제풀이

Today
Yesterday
Total
  • [13907] 세금
    BOJ 2021. 11. 3. 07:03

    https://www.acmicpc.net/problem/13907

     

    13907번: 세금

    첫 번째 줄에 세 정수 N (2 ≤ N ≤ 1,000), M (1 ≤ M ≤ 30,000), K (0 ≤ K ≤ 30,000)가 주어진다. 각각 도시의 수, 도로의 수, 세금 인상 횟수를 의미한다. 두 번째 줄에는 두 정수 S와 D (1 ≤ S, D ≤ N, S ≠ D

    www.acmicpc.net

    <문제>

    다소 구현이 까다로운데, 정해를 떠올리기 위해 필요한 관찰은 어렵지 않다.

    시작 정점 S에서 도착 정점 E까지 지나간 간선의 개수를 알고 있다면,

    다익스트라를 다시 돌리거나 인접리스트를 건드리지 않아도 O(1)만에 세금을 적용한 비용을 알 수 있다.

    시작에는 최적해였던것이 세금을 적용한 후에는 최적해가 아닐 수 있으므로, S를 제외한 집합에 대해서

    모든 경로를 다 저장해둘 필요가 있겠다. 그렇기에 기존의 다익스트라에서 dist[]를 dist[][]로 확장하여

    dist[i][j] : i번 정점을 j개의 간선을 지났을때의 최소비용으로 채워준다.

     

    다익스트라는 전체에서 한번만 호출하고, 인접리스트도 입력에서만 유일하게 수정하며

    각 쿼리마다 dist[e][1...N]을 순회하여 최소값을 찾음으로써, 쿼리당 O(N)으로 해를 구할 수 있다.

    가령 dist[e][6]을 참조할때에는, score = 6*tax + dist[e][6]으로 계산하여 세금적용 후 비용을 찾는다.

     

    <소스코드>

    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
    #include <bits/stdc++.h>
    using namespace std;
    const int INF = 1e9;
    using pi = pair<intint>;
    using ll = long long;
    vector<pi> adj[1001];
    int dist[1005][1005];
    int n, m, k, s, e;
    struct state {
        int node, cost, cnt;
    };
    struct cmp {
        bool operator()(state& a, state& b) { return a.cost > b.cost; }
    };
    void f(void) {
        int i, j;
        for (i = 1; i <= 1000; i++) {
            for (j = 1; j <= 1000; j++) {
                dist[i][j] = INF;
            }
        }
        dist[s][0= 0;
        priority_queue<state, vector<state>, cmp> q;
        q.push({s, 00});
        while (!q.empty()) {
            auto cur = q.top();
            q.pop();
            if (cur.cost > dist[cur.node][cur.cnt]) continue;
            for (auto& next : adj[cur.node]) {
                int nCost = next.first;
                int nNode = next.second;
                if (dist[nNode][cur.cnt + 1> cur.cost + nCost) {
                    dist[nNode][cur.cnt + 1= cur.cost + nCost;
                    q.push({nNode, cur.cost + nCost, cur.cnt + 1});
                }
            }
        }
        return;
    }
    int solve(int tax) {
        int i, ans = INF;
        for (i = 1; i <= 1000; i++) {
            ll score = ((ll)i * (ll)tax) + (ll)dist[e][i];
            if (score <= INT_MAX) ans = min((int)score, ans);
        }
        return ans;
    }
    int main(void) {
        ios_base::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        cin >> n >> m >> k;
        cin >> s >> e;
        int i, j;
        for (i = 0; i < m; i++) {
            int a, b, c;
            cin >> a >> b >> c;
            adj[a].push_back({c, b});
            adj[b].push_back({c, a});
        }
        f();
        cout << solve(0<< '\n';
        int x = 0, taxPsum = 0;
        while (k--) {
            cin >> x;
            taxPsum += x;
            cout << solve(taxPsum) << '\n';
        }
        return 0;
    }
    cs

     

    'BOJ' 카테고리의 다른 글

    [1992] 쿼드트리  (0) 2021.11.04
    [1700] 멀티탭 스케줄링  (0) 2021.11.04
    [17267] 상남자  (0) 2021.11.03
    [2842] 집배원 한상덕  (0) 2021.11.02
    [1311] 할 일 정하기 1  (0) 2021.11.01

    댓글