pat 公路村村通--最新小生成树

公路村村通   (30分)

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数NNN≤1000\le 10001000)和候选道路数目MMM≤3N\le 3N3N);随后的MMM行对应MMM条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到NNN编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1-11,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

本题就是求图的最小生成树
使用vector做邻接表存储图
我用的是krusal算法,我们先把给出的边按照权值排序,然后每次选择权值最小的边,这里要判断是不是边选重了(即连接边的点被选了2次),用并查集判断,知道选择出n-1条边

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef struct Bian{
	int v1,v2;
	int w;     ///权值
}bian;
int n,m;
int f[1001];   ///并查集使用的数组
bool cmp(const bian a,const bian b){
	return a.w < b.w;
}
void init(){
	for(int i = 1; i <= 1001; ++i){
		f[i] = i;
	}
}
int getf(int a){     ///并查集里寻找祖先
    if(a == f[a]) return a;
    return f[a] = getf(f[a]);
}
int merge(int a,int b){   ///并查集的合并
    int ta,tb;
    ta = getf(a);
    tb = getf(b);
    if(ta == tb) return 0;
    f[ta] = tb;
    return 1;
}
int main(int argc, char *argv[]) {
	int ans = 0;
	int count = 0;
	vector<bian> v;
	init();
	scanf("%d%d",&n,&m);
	getchar();
	int temp = m;
	while(m--){    ///边的输入,构建图的邻接表
		bian tmp1;
		int x,y,ww;
		scanf("%d%d%d",&x,&y,&ww);
		tmp1.v1 = x;
		tmp1.v2 = y;
		tmp1.w = ww;
		v.push_back(tmp1);
	}
	sort(v.begin(),v.end(),cmp);    ///根据权值对边排序
	for(int i = 0; i < v.size(); ++i){
		int t = merge(v[i].v1,v[i].v2);
		if( t ){
			ans += v[i].w;
			count++;
		}
		if(count == n-1) break;
	}
	if(count != n-1) printf("-1\n");   ///如果最后没有选出n-1条边,那么只能是条件不够
	else 
	    printf("%d\n",ans);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/shengsikandan/article/details/51203829