题解:跑一遍最小生成树,因为每条边长度不同所以跑不出来的答案就只有一种,对于求解任意两点的期望,只要把任意两点的距离累加和再除以总数即可,对于计算累加和,我借鉴了别人的方法,对于每条边,算出它左边有n个点,右边有m个点,那么这条边就会被用到n*m次 ,对所有的边都这么算一遍,答案累加就可以了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
#include <queue>
#include <climits>
#include <stack>
using namespace std;
struct node {
int op, ed;
int len;
bool operator<(const node &x)const{
return len < x.len;
}
}edge[1000005];
int father[100005], ret[1000005], dep[100005];
int cnt;
int n, m;
vector<int> graph[100005];
int find_(int x)
{
if(father[x] == x)
return x;
else
return father[x] = find_(father[x]);
}
int dfs(int now, int pre)
{
int ans = 1;
for(int i = 0; i < graph[now].size(); i++){
if(graph[now][i] != pre)
ans += dfs(graph[now][i], now);
}
dep[now] = ans;
return ans;
}
void init()
{
for(int i = 1; i <= n; i++)
father[i] = i;
memset(dep, 0, sizeof(dep));
}
long long kruskal()
{
long long answer = 0;
sort(edge, edge + m);
for(int i = 0; i < m; i++){
int a = edge[i].op, b = edge[i].ed;
int x = find_(a), y = find_(b);
if(x == y) continue;
father[x] = y;
ret[cnt++] = i;
answer += edge[i].len;
graph[a].push_back(b);
graph[b].push_back(a);
if(cnt == n - 1) break;
}
return answer;
}
int main()
{
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
graph[i].clear();
cnt = 0;
for(int i = 0; i < m; i++)
scanf("%d %d %d", &edge[i].op, &edge[i].ed, &edge[i].len);
init();
long long ans1 = kruskal();
double sum1 = 0;
dfs(1, -1);
for(int i = 0; i < cnt; i++){
int x = edge[ret[i]].op, y = edge[ret[i]].ed;
int tmp = min(dep[x], dep[y]);
int maxn = n - tmp;
sum1 += 1ll * tmp * maxn * edge[ret[i]].len;
}
printf("%lld %.2lf\n", ans1, sum1 / (1ll * n * (n - 1) / 2));
}
return 0;
}