算法实验11:还是畅通工程(最小生成树 kruscal prim)
算法实验11:还是畅通工程
Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
Sample Output
3 5
-
kruscal
给边从小到大排序,判断该条边的两端点是否属于同一个祖先(同一个连通子集),是的话跳过,否则选上
#include <iostream> #include <algorithm> using namespace std; const int inf = 0x3f3f3f3f; struct Node { int a,b,c; }edge[100005]; bool cmp(Node p,Node q) { return p.c < q.c; } int fa[105]; int find_(int a) { int x = a; while(x!=fa[x]){ x = fa[x]; } fa[a] = x; return x; } void union_(int x,int y) { int fx = find_(x); int fy = find_(y); if(fx != fy) { fa[fy] = fx; } } int main() { int n,m; while(cin >> n&&n) { m = n*(n-1)/2; for(int i = 0; i < m; i++) { cin >> edge[i].a >> edge[i].b >> edge[i].c; } sort(edge,edge+m,cmp); for(int i = 1; i <= n; i++) fa[i] = i; int ans = 0,sum = 0; for(int i = 0; i < m; i++) { if(sum == n-1) break; if(find_(edge[i].a) != find_(edge[i].b)) { sum++; ans += edge[i].c; union_(edge[i].a,edge[i].b); } } cout << ans << endl; } return 0; }
-
prim
设两个数组a[i],b[i],a[i]表示起点为b[i],终点为i的边的权值 假设一开始的起点都为1
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int inf = 0x3f3f3f3f; int edge[105][105]; int a[105],b[105]; int main() { int n,m; while(cin >> n&&n) { m = n*(n-1)/2; memset(edge,inf,sizeof(inf)); int u,v,w; for(int i = 0; i < m; i++) { cin >> u >>v >>w; edge[u][v] = w; edge[v][u] = w; } a[1] = 0,b[1] = 0; int ans = 0; for(int i = 2; i <= n; i++) a[i] = edge[1][i],b[i] = 1; for(int i = 2; i <= n; i++) { int maxn = inf,k; for(int j = 1; j <= n; j++) { if(a[j] < maxn && a[j] != 0) { maxn = a[j]; k = j; } } ans += maxn; a[k] = 0,b[k] = 0; for(int j = 1; j <= n; j++) { if(a[j] > edge[k][j]) { b[j] = k; a[j] = edge[k][j]; } } } cout << ans << endl; } return 0; }