Submission #1288212

#TimeUsernameProblemLanguageResultExecution timeMemory
1288212phunghaCities (BOI16_cities)C++20
100 / 100
1213 ms40500 KiB
#include <bits/stdc++.h>
using namespace std;

int n, k, m, city[5];
vector<pair<int, int>> g[100001];
long long d[32][100001];

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    //freopen("test24.in", "r", stdin);
    //freopen("test01.out", "w", stdout);
    cin >> n >> k >> m;
    for (int i = 0; i < k; i++) {
        cin >> city[i];
        city[i]--; // chuyển về chỉ số 0
    }
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        a--; b--; // chuyển về chỉ số 0
        g[a].push_back({b, c});
        g[b].push_back({a, c});
    }

    /*
    d[mask][v] = chi phí nhỏ nhất để tạo một miền liên thông (một cây con) kết nối các đỉnh quan trọng trong mask
    và tập đó kết thúc / gom về tại đỉnh v:
        + mask là bitmask trên k đỉnh quan trọng (bit i = 1: tập này đã kết nối chứa thành phố quan trọng thứ i)
        + v là một đỉnh bất kỳ trong đồ thị (0..n-1)
    khởi tạo toàn bộ mảng d với +oo
    khởi tạo trạng thái ban đầu, với mỗi thành phố quan trọng city[i]:
        + mask chỉ chứa duy nhất bit i: (1 << i)
        + chi phí để kết thúc ở chính nó là 0 (không cần cạnh nào)
    */
    for (int i = 0; i < (1 << k); i++)
        for (int j = 0; j < n; j++)
            d[i][j] = 1e18;
    for (int i = 0; i < k; ++i)
        d[1 << i][city[i]] = 0;

    // duyệt qua tất cả các mask khác 0 (1..(1<<k)-1)
    for (int mask = 1; mask < (1 << k); mask++) {
        // 1) Subset DP: ghép các tập con a và b của mask để cải thiện d[mask][v]
        // a là một tập con của mask
        for (int a = 0; a <= mask; a++) {
            if ((a | mask) != mask) continue; // điều kiện a là tập con của mask
            int b = mask ^ a;                 // b là tập con còn lại (b = mask \ a)
            if (b > a) continue;              // tránh đếm lặp (a, b) và (b, a)

            // với mỗi đỉnh v, ghép hai cây con có cùng "điểm tụ" v
            // d[mask][v] = min(d[mask][v], d[a][v] + d[b][v])
            for (int v = 0; v < n; v++)
                d[mask][v] = min(d[mask][v], d[a][v] + d[b][v]);
        }

        // 2) Dijkstra đa nguồn cho tập nguồn mask
        // Sau bước ghép ở trên, d[mask][v] hiện tại là chi phí tốt nhất để kết nối mask và "tụ" tại v, nhưng chưa lan qua các cạnh
        // pq là hàng đợi ưu tiên cho dijkstra: lưu (-cost, v) để dùng max-heap giả lập min-heap
        // đẩy các đỉnh v có d[mask][v] < +oo vào priority queue làm nguồn ban đầu
        priority_queue<pair<long long, int>> pq;
        for (int v = 0; v < n; v++)
            if (d[mask][v] < 1e18)
                pq.push({-d[mask][v], v});
        // chạy dijkstra với các nguồn đa điểm
        while (!pq.empty()) {
            long long cur_d = -pq.top().first;
            int v = pq.top().second;
            pq.pop();
            if (cur_d > d[mask][v]) continue; // đã xử lý v rồi
            for (auto [u, w]: g[v]) // relax tất cả các cạnh xuất phát từ v
                if (d[mask][u] > d[mask][v] + w) {
                    d[mask][u] = d[mask][v] + w;
                    pq.push({-d[mask][u], u});
                }
        }
    }

    // kết quả là min(d[(1 << k) - 1][v] với mọi v = 0..n-1)
    long long ans = 1e18;
    int full_mask = (1 << k) - 1;
    for (int v = 0; v < n; ++v)
        ans = min(ans, d[full_mask][v]);
    cout << ans << "\n";
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...