Abandoned country
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 825 Accepted Submission(s): 221
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.
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
题解链接http://bestcoder.hdu.edu.cn/blog/2016-multi-university-training-contest-1-solutions-by-hit/
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const long long int maxn=1e6+666;
struct node
{
long long int u;//u到v权值w
long long int v;
long long int w;
} Edges[maxn],edge[maxn*2]; //用于最小生成树与邻接表
long long int first[maxn];//邻接表数组
long long int nextn[maxn];
long long int point[maxn];//第i个点的子树被用了point[i]次
bool vis[maxn];//已访问标记为1
long long int Father[maxn];//并查集数组
long long int N;//点的数量
long long int M;//边的数量
long long int num_Edges;//已添加进生成树的边的数量
long long int len_Edges;//添加进邻接表的边的数量;
long long int sum_Edges;//枚举任意两点时用过的边的权值
void init()//初始化并查集
{
for(int i=0; i<=N; i++)
{
Father[i]=i;
first[i]=-1;
point[i]=1;
vis[i]=0;//置为未访问
}
num_Edges=0;//已添加进生成树的边的数量
len_Edges=0;//添加进邻接表的边的数量
sum_Edges=0;//用过权值的总和
}
long long int Query(long long int x)//查询x的父亲
{
if(x!=Father[x])
Father[x]=Query(Father[x]);
return Father[x];
}
bool Merge(long long int x,long long int y)//合并x和y
{
long long int flag_x=Query(x);
long long int flag_y=Query(y);
if(flag_x!=flag_y)
{
Father[flag_x]=flag_y;
return true;
}
return false;
}
bool cmp(node x,node y)
{
return x.w<y.w;
}
void ADD_Edges(long long int u,long long int v,long long int w)//u到v权值w
{
edge[len_Edges].u=u;
edge[len_Edges].v=v;
edge[len_Edges].w=w;
nextn[len_Edges]=first[u];
first[u]=len_Edges;
len_Edges++;
}
void DFS(long long int now)
{
long long int k=first[now];
while(k+1)
{
if(vis[edge[k].v]==false)
{
vis[edge[k].v]=true;
DFS(edge[k].v);
sum_Edges+=edge[k].w*point[edge[k].v]*(N-point[edge[k].v]);
point[now]+=point[edge[k].v];
}
k=nextn[k];
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d",&N,&M);
init();
for(int i=0; i<M; i++)
scanf("%I64d%I64d%I64d",&Edges[i].u,&Edges[i].v,&Edges[i].w);
sort(Edges,Edges+M,cmp);
long long int min_cost=0;//定义最小花费
for(int i=0; i<M; i++)
{
if(Merge(Edges[i].u,Edges[i].v))
{
num_Edges++;
min_cost+=Edges[i].w;
ADD_Edges(Edges[i].u,Edges[i].v,Edges[i].w);
ADD_Edges(Edges[i].v,Edges[i].u,Edges[i].w);
}
if(num_Edges==N-1)//最小生成树由N-1条边构成
break;
}
memset(vis,false,sizeof(vis));
vis[1]=true;
DFS(1);
printf("%I64d %.2lf\n",min_cost,sum_Edges*1.0/((N*(N-1)/2)));//注意输出
}
return 0;
}