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飞。
我们考虑建立一个超级原点,将每个点的点权设置为这个点到原点的边权(

浙公网安备 33010602011771号