Loading

7.19测

题面、数据、样例点这里

T1

题面概述

给定一张图,求1~n间所有路径中,路径上的最大边权和最小边权和的最小值

题目分析

首先想到暴力,dfs暴力找到所有路径,然后暴力求出最大边权和最小边权差,然后取最小值。(当然会T飞)

然后,聪明的你想到了Kruskal算法,于是想到对于每条边从小到大依次考虑,逐条加边,此时,我们的路径的最大边权就当前边权,同时我们统计每个连通块的最小边权,每次merge我们更新答案为\(\min(ans,min\_edge_u,min\_edge_v)\),显然这个贪心是正确的,我们从小到大加边,当1和n连通时,一定和为最小值(口胡这一块

Code

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
int n, m;
pair<int, pair<int, int>> edge[N];
int fa[N];
int min_edge[N];

int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void merge(int x, int y, int w) {
    x = find(x), y = find(y);
    if (x != y) {
        fa[y] = x;
        min_edge[x] = min(min_edge[x], min(min_edge[y], w));
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        edge[i] = {z, {x, y}};
    }

    sort(edge + 1, edge + m + 1);

    for (int i = 1; i <= n; i++) {
        fa[i] = i;
        min_edge[i] = INT_MAX; // 初始化为极大值
    }

    int ans = INT_MAX;
    for (int i = 1; i <= m; i++) {
        int w = edge[i].first;
        int u = edge[i].second.first;
        int v = edge[i].second.second;
        merge(u, v, w);
        if (find(1) == find(n)) {
            ans = min(ans, w + min_edge[find(1)]);
        }
    }

    cout << ans << "\n";
    return 0;
}

T2

T3

T4

题目概述

给定一张无向图,图有边权,点权。
从每个点i出发,到达每个点,求\(\min_{j=1}^nd(i,j)+a_j,i可以等于j\),其中\(d(i,j)\)表示i到j的最短路径距离,\(a_i\)表示点权。

题目分析

同样显然,我们可以从每个点跑一遍Dijstrastra,然后统计答案。但同样显然会T飞。

我们考虑建立一个超级原点,将每个点的点权设置为这个点到原点的边权(

posted @ 2025-07-19 15:24  Venlacy  阅读(46)  评论(0)    收藏  举报