简单题意
原来的路网被废弃,现在要最小花费的重建,并求出新的路中任意两点距离的期望
思路
先用最小生成树得到最小花费的新路,然后DFS搜索一遍的到每个节点的子节点个数,这样就可以算出每条路被使用的次数是sub[i] * (n - sub[i]),最后就可以算出总的期望了
代码
#include <bits/stdc++.h>
using namespace std;
const int maxm = 1e6 + 10;
const int maxn = 1e5 + 10;
typedef long long ll;
struct Edges{
int u,v,w;
Edges(){};
Edges(int u,int v,int w):u(u),v(v),w(w){};
bool operator < (const Edges & b) const {
return w < b.w;
}
}edge[maxm];
int fa[maxn];
vector<Edges> G[maxn],V;
int Find(int x){
return fa[x] == x ? x :fa[x] = Find(fa[x]);
}
bool Union(int x ,int y){
x = Find(x);
y = Find(y);
if(x == y) return false;
fa[x] = y;
return true;
}
ll lent = 0;
inline addedge(Edges & e){
G[e.u].push_back(e);
G[e.v].push_back(Edges(e.v,e.u,e.w));
lent += e.w;
}
int cnt[maxn];
int dfs(int cur,int from){
for(int i = 0 ; i < G[cur].size() ; i ++){
Edges & e = G[cur][i];
if(e.v == from) continue;
cnt[cur] += dfs(e.v,cur);
}
return cnt[cur];
}
void init(int n){
for(int i = 0 ; i <= n ; i ++){
G[i].clear();
cnt[i] = 1;
fa[i] = i;
}
V.clear();
lent = 0;
}
int main (){
int T;
cin >>T;
while (T --){
int n,m;
scanf("%d %d", &n,&m);
init(n);
for(int i = 0 ; i < m ; i ++){
int u,v,w;
scanf("%d %d %d", &u,&v,&w);
edge[i] = Edges(u,v,w);
}
sort(edge,edge+m);
for(int i = 0 ; i < m ; i ++){
Edges & e = edge[i];
if(Union(e.u,e.v)) {
addedge(e);
V.push_back(e);
}
}
dfs(1,-1);
double exp = 0;
for(int i = 0 ; i < V.size() ; i ++){
Edges & e = V[i];
int tmp = min(cnt[e.u],cnt[e.v]);
exp += 1LL * tmp * (n-tmp)*e.w;
}
printf("%I64d %.2f\n", lent, exp/(n-1)/n*2);
}
}