网易笔试8.8(生成树最大权值与最小权值之差最小)
#include <bits/stdc++.h>
using namespace std;
struct Edge{
int u, v;
int w;
};
bool inSameSet(int *uni, int r1, int r2) {
while(r1 != uni[r1]) r1 = uni[r1];
while(r2 != uni[r2]) r2 = uni[r2];
if(r1 == r2) return true;
uni[r1] = r2;
return false;
}
int solution() {
int n, m;
cin >> n >> m;
//顶点为1时,边数自然为0
if(n == 1)
return 0;
int uni[n+1];
for(int i = 1; i<=n; ++i) uni[i] = i;
Edge edge[m];
for(int i = 0; i<m; ++i) {
cin >> edge[i].u >> edge[i].v >> edge[i].w;
}
sort(edge, edge+m, [](Edge& a, Edge& b) {
return a.w < b.w;
});
int l, r, dw = n-2, min_d = INT_MAX;
for(int i = dw; i<m; ++i) {
if(edge[i].w - edge[i-dw].w < min_d) {
r = i;
min_d = edge[i].w - edge[i-dw].w;
}
}
l = r-dw;
//先加l, l+1, ..., r这n-1条边,看是否构成树
int cnt = 0; //加入的边数
for(int i = l; i<=r; ++i) {
if(!inSameSet(uni, edge[i].u, edge[i].v)) {
++cnt;
}
}
//若边数cnt小于n-1则还得往两边去找边加入到集合中,直到找到n-1条边
while(l >= 0 && r<n && cnt < n-1) {
if(l == 0) {
++r;
if(r<n && !inSameSet(uni, edge[r].u, edge[r].v)) {
++cnt;
}
} else if(r == n-1) {
--l;
if(l>=0 && !inSameSet(uni, edge[l].u, edge[l].v)) {
++cnt;
}
} else {
if(edge[r].w - edge[l-1].w < edge[r+1].w -edge[l].w) {
--l;
if(!inSameSet(uni, edge[l].u, edge[l].v)) ++cnt;
} else{
++r;
if(!inSameSet(uni, edge[r].u, edge[r].v)) ++cnt;
}
}
}
return edge[r].w - edge[l].w;
}
int main()
{
cout << solution() << endl;
return 0;
}
题目描述:有一张n个顶点m条边的无向图,每条边一个权值。
牛牛希望构造一棵生成树(既保留n-1条边,单保持图连通),使得最大边权减去最小边权的值最小。
输入:2 1
1 2 100
输出: 0
解释:第一行为该图顶点数为n = 2,边数 m = 1,后面的m行为边的信息,1 2 100 表示边(1, 2)的权值为100
#笔试题目##网易#