P15818 [JOI 2015 Final] JOI 公园 / JOI Park

题面

题目解析

直接上代码,你绝对看得懂!

// 地道被我写成了通道,看得懂就好
#include <bits/stdc++.h>

using namespace std;

#define int long long

constexpr int N = 1e5 + 2;

vector<pair<int, int>> a[N];
bool f[N], u[N];
int d[N];

pair<int, int> b[N];

inline void dij() { // 板子
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
    memset(d, 127, sizeof d);
    d[1] = 0;
    q.push({0, 1});
    while (!q.empty()) {
        auto t = q.top();
        q.pop();
        int now = t.second;
        if (d[now] < t.first) continue;
        if (f[now]) continue;
        f[now] = true;

        for (auto i : a[now]) {
            int x = i.first, y = i.second;
            if (d[now] + y < d[x]) {
                d[x] = d[now] + y;
                q.push({d[x], x});
            }
        }
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int n, m, c;
    cin >> n >> m >> c;

    int tot = 0; // 所有边权总和,在后面是没进入通道的边权总和
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        a[u].push_back({v, w});
        a[v].push_back({u, w});
        tot += w;
    }

    dij();

    for (int i = 1; i <= n; i++) {
        b[i] = {d[i], i}; // 为了排序,x小的点一定会先一步有通道,随着x的增大这些始终在通道里
    }
    sort(b + 1, b + n + 1);
    int ans = tot;
    for (int i = 1; i <= n; i++) {
        int sy = b[i].second; 
        u[sy] = true;

        for (auto e : a[sy]) {
            if (u[e.first]) {
				// 如果sy和e.first都和和通道接触的点,那么他们的道路就可以拆掉,因为加入了通道
                tot -= e.second; // 在通道里
            }
        }

        ans = min(ans, tot + c * b[i].first); // 更新最小花费
    }

    cout << ans;

    // for (int i = 1; i <= n; i++) {
    //     cout << d[i] << " ";
    // }
}

别忘了点赞

posted @ 2026-04-10 21:08  PCMSFV  阅读(2)  评论(0)    收藏  举报