// 求最小生成树 // 克鲁斯卡尔算法kruskal:从边集合中,从小到大筛选,若两端点不属于同一集合,加入该边 // 1.若该图已经连通,退出循环输出结果 // 2.或者循环完所有边,输出结果 #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Edge { int from; int to; int length; }; vector<Edge> edge;//装入所有边 int n; //并查集算法start const int maxn=27; int father[maxn]; int height[maxn]; void init(int n){ for(int i=0; i<n;i++) { father[i]=i; height[i]=0; } } int find(int x){ if(x!=father[x]){ father[x]=find(father[x]); } return father[x]; } void Union(int x,int y){ x=find(x); y=find(y); if(x!=y){ if(height[x]<height[y]){ father[x]=y; } else if(height[x]>height[y]){ father[y]=x; } else{ father[y]=x; height[x]++; } } } //求连通分量 int countFather(int n){ int count=0; for(int i=0;i<n;i++){ if(i==find(i)) count++; } return count; } //并查集算法end bool comp(Edge x,Edge y){ return x.length<y.length; } void kruskal(int num_of_dot){ int total=0; init(num_of_dot); for(auto x:edge){ //两端点若不都在集合内,加入该边 if(find(x.from)!=find(x.to)){ Union(x.from,x.to); total+=x.length; } //如果已经连通,直接输出返回 if(countFather(num_of_dot)==1){ cout<<total<<endl; return; } } //遍历完所有的边任然不连通 cout<<total<<endl; return; } int main(){ while (cin>>n) { edge.clear(); if(n==0) break; //输入 for(int i=0;i<n-1;i++){ char head,foot; int num,number,length; cin>>head>>num; for(int j=0;j<num;j++){ cin>>foot>>length; Edge e; e.from=head-'A'; e.to=foot-'A'; e.length=length; edge.push_back(e); } } //按边长度从小到大排序 sort(edge.begin(),edge.end(),comp); //克鲁斯卡尔算法 kruskal(n); } }