题目大意:有n(n<100000)个地点面m(m<1000000)条路,修每条路都有花费w,求最小花费使每个地点能够互相到达并求出人一两点的花费期望;
因为n很大所以用kruskal求最小生成树求出最小花费,然后dfs搜索回溯的办法找到所有情况每条路用过的次数并求出总花费,用总花费除以所有可能发生的次数(n*(n-1)/2)就是我们要求的期望。
其中用到vector容器进行dfs;
#include<bits/stdc++.h>
#define LL long long
const int NN=1e6+10;
using namespace std;
int bin[NN];
int dp[NN];
int vis[NN];
int n,m;
struct node{
int no;
int to;
int val;
bool operator <(const node &p1)const{
return val<p1.val;
}
}p[NN];
struct node1{
int to;
int val;
}now;
vector<node1> edge[NN];
int Find(int x){
return x==bin[x]?x:bin[x]=Find(bin[x]);
}
long long ans=0;
int DFS(int x){
if(vis[x])return dp[x];
dp[x]=1;
vis[x]=1;
int len=edge[x].size();
for(int i=0;i<len;i++){
int to=edge[x][i].to;
int val=edge[x][i].val;
if(vis[to]==0){
dp[x]+=DFS(to);
ans=ans+(LL)(dp[to])*(LL)(n-dp[to])*val;
}
}
return dp[x];
}
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(vis,0,sizeof(vis));
memset(edge,0,sizeof(edge));
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d%d",&p[i].no,&p[i].to,&p[i].val);
}
sort(p,p+m);
for(int i=0;i<=n;i++){
bin[i]=i;
}
ans=0;
long long sum=0;
int cnt=0;
for(int i=0;i<m;i++){
int fx=Find(p[i].no);
int fy=Find(p[i].to);
if(fx!=fy){
bin[fx]=fy;
sum+=p[i].val;
now.to=p[i].to;
now.val=p[i].val;
edge[p[i].no].push_back(now);
now.to=p[i].no;
edge[p[i].to].push_back(now);
cnt++;
if(cnt==n-1) break;
}
}
DFS(1);
printf("%lld %.2f\n",sum,ans*2.0/((double)n*(n-1)));
}
return 0;
}