Problem Description
An abandoned country has
n(n≤100000)
villages which are numbered from 1 to
n
. Since abandoned for a long time, the roads need to be re-built. There are
m(m≤1000000)
roads to be re-built, the length of each road is
wi(wi≤1000000)
. Guaranteed that any two
wi
are different. The roads made all the villages connected directly or indirectly before destroyed. Every road will cost the same value of its length to rebuild. The king wants to use the minimum cost to make all the villages connected with each other directly or indirectly. After the roads are re-built, the king asks a men as messenger. The king will select any two different points as starting point or the destination with the same probability. Now the king asks you to tell him the minimum cost and the minimum expectations length the messenger will walk.
Input
The first line contains an integer
T(T≤10)
which indicates the number of test cases.
For each test case, the first line contains two integers n,m indicate the number of villages and the number of roads to be re-built. Next m lines, each line have three number i,j,wi , the length of a road connecting the village i and the village j is wi .
For each test case, the first line contains two integers n,m indicate the number of villages and the number of roads to be re-built. Next m lines, each line have three number i,j,wi , the length of a road connecting the village i and the village j is wi .
Output
output the minimum cost and minimum Expectations with two decimal places. They separated by a space.
Sample Input
1 4 6 1 2 1 2 3 2 3 4 3 4 1 4 1 3 5 2 4 6
Sample Output
6 3.33
题意:
n个点,m个边,输入m个边,a,b,c表示a,b之间有条权值为c的无向边。选择n-1条边使得n个点联通并且总权值最小。此时,随机选择不同的两点,求两点之间路径长度的期望。
分析:
显然,先使用最小生成树选择n-1条边,期望可以这样算,把所有选择情况全部算上每次选择的路径长度相加总和除以选择总数即为每次选择的期望。
选择总数很显然为C(2,n) = n(n-1)/2;总和怎么算呢?我们可以把所有选择情况的路径和看作是在所有选择情况中每条边被选择的次数乘以自身权值然后所有边求和。那么问题就转化为每条边会被选择多少次。其实仔细发现对于一个边的左子树和右子树,从两边各选一个点,这两点的路径一定经过该边。那么问题转化为求一个边的左子树和右子树大小。因为两子树大小子和一定是n,所以只需要求一边的子树大小。这样我们就可以用dfs,回溯到该点就可以知道该点为根节点的子树大小。
#include<stdio.h>
#include<string.h>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
struct edge
{
int u,v,w;
}e[1000100];
int f[100100];
vector< pair<int,int> > mpt[100100];
bool visit[100100];
int n,m;
long long ans;
void Init()
{
for(int i = 1 ; i <= n ; i ++)f[i] = i;
}
int Find(int x)
{
if(x == f[x]) return x;
return f[x] = Find(f[x]);
}
bool cmp(edge& a,edge& b)
{
return a.w < b.w;
}
int dfs(int index)
{
visit[index] = true;
int cnt = 1;
for(int i = 0 ; i < mpt[index].size() ; i ++)
{
int next = mpt[index][i].first;
if(visit[next]) continue;
int rest = dfs(next);
ans = ans + (long long)mpt[index][i].second * rest * (n - rest);
cnt += rest;
}
return cnt;
}
int main()
{
int t;
cin >> t;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i = 0 ; i < m ; i ++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e,e+m,cmp);
Init();
int cnt = 0;
long long sum = 0;
for(int i = 1 ; i <= n ; i ++)
mpt[i].clear();
for(int i = 0 ; i < m ; i ++)
{
if(Find(e[i].u) != Find(e[i].v))
{
cnt ++;
f[f[e[i].u]] = f[e[i].v];
mpt[e[i].u].push_back(pair<int,int>(e[i].v,e[i].w));
mpt[e[i].v].push_back(pair<int,int>(e[i].u,e[i].w));
sum += e[i].w;
}
if(cnt == n - 1) break;
}
ans = 0;
memset(visit,0,sizeof(visit));
for(int i = 1 ; i <= n ; i ++)
if(mpt[i].size() == 1)
{
dfs(i);
break;
}
printf("%lld %.2lf\n",sum,(double)ans * 2.0/n/(n-1));
}
return 0;
}
注意:题目数据范围可能会超int。