题目连接
一道可以暴力水过去的次小生成树
首先用 K r u s k a l Kruskal Kruskal|| P r i m Prim Prim求出原图的一颗最小生成树,在连边的时候,用一个 v i s vis vis记录一下那些已经在最小生成树里面。
提前暴力 d f s dfs dfs或者 b f s bfs bfs求出任意两点构成的环之间的最大权值
定义函数 d f s ( i n t s , i n t u , i n t f a t h e r , i n t m w 1 , i n t m w 2 ) dfs(int s, int u, int father, int mw1, int mw2) dfs(ints,intu,intfather,intmw1,intmw2)
s -> 起点 u -> 终点 father 判断是否回到原起点 mw1 最大值 mw2 次大值
再用md1[s][u]保存从s -> u的最大边权值, 用md2[s][u]保存从s -> u的次大边权值
循环遍历与重点u相连接的每一个点(v),如果没有回到father就继续。
定义t1, t2
如果 从u -> v的 权值(w) 大于了现在的mw1
- 把t1 更新为 w
- 把t2 更新为 mw1
否则 如果 w 大于了现在的mw2 并且小于 mw1
- 把t1 更新为 mw1
- 把t2 更新为 w
最后递归遍历 dfs(s, v, u, t1, t2)
再一次考虑每一条非树边,用这条边上的权值考虑替换原边
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 505;
const int MAXM = 1e4 + 5;
long long n, m, tot, fa[MAXN], md1[MAXN][MAXN], md2[MAXN][MAXN];
long long ans, sum;
bool vis[MAXN];
struct node {
long long u, v, w;
bool vis;
} dis[MAXM];
bool cmp(node x, node y) {
return x.w < y.w;
}
struct edge {
int v, w;
edge() {}
edge(int V, int W) {
v = V;
w = W;
}
};
vector<edge> G[MAXN];
void AddEdge(int u, int v, long long w) { G[u].push_back(edge(v, w)); }
int FindSet(int v) {
if (fa[v] == v)
return fa[v];
else
return fa[v] = FindSet(fa[v]);
}
bool UnionSet(int u, int v) {
int x = FindSet(u);
int y = FindSet(v);
if (x == y)
return 0;
else {
fa[x] = fa[y];
return 1;
}
}
void dfs(int s, int u, int fa, int mw1, int mw2) {
md1[s][u] = mw1;
md2[s][u] = mw2;
for (int j = 0; j < G[u].size(); j++) {
int v = G[u][j].v;
int w = G[u][j].w;
if (v != fa) {
int t1, t2;
if (w > mw1) {
t1 = w;
t2 = mw1;
} else if (w < mw1 && w > mw2) {
t1 = mw1;
t2 = w;
}
dfs (s, v, u, t1, t2);
}
}
}
void Kruskal() {
for (int i = 1; i <= n; i++) fa[i] = i;
sort(dis + 1, dis + 1 + m, cmp);
for (int i = 1; i <= m; i++) {
if (UnionSet(dis[i].u, dis[i].v)) {
sum += dis[i].w;
tot++;
dis[i].vis = 1;
AddEdge(dis[i].u, dis[i].v, dis[i].w);
AddEdge(dis[i].v, dis[i].u, dis[i].w);
}
if (tot == n - 1)
break;
}
for (int i = 1; i <= n; i++) {
dfs (i, i, -1, 0, 0);
}
ans = 1e19;
for (int i = 1; i <= m; i++) {
if (dis[i].vis == 0) {
int w = dis[i].w, u = dis[i].u, v = dis[i].v;
if (w > md1[u][v]) ans = min(ans, sum + w - md1[u][v]);
else if (w > md2[u][v]) ans = min(ans, sum + w - md2[u][v]);
}
}
printf ("%lld\n", ans);
}
int main() {
scanf("%lld %lld", &n, &m);
for (int i = 1; i <= m; i++) {
scanf ("%lld %lld %lld", &dis[i].u, &dis[i].v, &dis[i].w);
}
Kruskal();
return 0;
}