An abandonedcountry has n(n≤100000) villageswhich are numbered from 1 to n. Since abandonedfor a long time, the roads need to be re-built. There are m(m≤1000000) roads to be re-built, the length ofeach road is wi(wi≤1000000). Guaranteed thatany two wi aredifferent. The roads made all the villages connected directly or indirectlybefore 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 witheach other directly or indirectly. After the roads are re-built, the king asksa men as messenger. The king will select any two different points as startingpoint or the destination with the same probability. Now the king asks you totell him the minimum cost and the minimum expectations length the messengerwill walk.
Input
The first linecontains an integer T(T≤10) which indicates the number of testcases.
For each test case, the first line contains two integers n,m indicate thenumber 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 minimumcost and minimum Expectations with two decimal places. They separated by aspace.
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
这个题的主要思路是最小生成树,关于生成树的说明以及代码模板如下:
普林(Prim)算法:普林算法和Dijkstra算法十分相似,都是从某个顶点出发,不断添加边的算法。首先我们假设一棵只包含一个顶点v的树T。然后贪心的选取T和其他顶点之间相连的最小权值的边,并把它加到T中。不断进行这个操作,就可以得到一棵生成树了。
其具体代码实现如下:
int cost[MAX_V][MAX_V];//cost[u][v]表示边e=(u,v)的权值(不存在的情况下设为INF)
int mincost[MAX_V]; //从集合X出发的边到每个顶点的最小权值
bool used[MAX_V]; //顶点i是否包含在集合X中
int V; //顶点数
int prim() {
for (int i = 0; i < V; ++i) {
mincost[i] = INF;
used[i] = false;
}
mincost[0] = 0;
int res = 0;
while(true){
int v = -1;
//从不属于X的顶点中选取X到其权值最小的顶点
for (int u = 0; u < V; u++) {
if (!used[u] && (v == -1 || mincost[u] < mincost[v]))
v = u;
}
if (v == 1) break;
used[v] = true;
res += mincost[v];
for (int u = 0; u < V; u++) {
mincost[u] = min(mincost[u], cost[v][u]);
}
}
return res;
}
克鲁斯卡尔(Kruskal)算法:
Kruskal算法按照边的权值的顺序从小到大查看一边,如不产生圈(重边等也算在内),就把当前这条边加入到生成树中。
其实现代码如下:
struct edge { int u, v, cost; };
bool comp(const edge& e1, const edge&e2) {
return e1.cost < e2.cost;
}
edge es[MAX_N];
int V, E; //顶点数和边数
int kruskal() {
sort(es, es + E, comp);//按照edge.cost的顺序从小到大排列
init_union_find(V); //并查集的初始化
int res = 0;
for (int i = 0; i < E; i++) {
edge e = es[i];
if (!same(e.u, e.v)) {
unite(e.u, e.v);
res += e.cost;
}
}
return res;
}