HDU多校联合训练 Problem1001 Abandoned country

Problem Description

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;
}


   

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值