题意:输入n个城市,下面n-1行;第一个字母代表该城市,第二个数字代表有几个城市与之相连的;后面的就是相连的城市及权值!
例:与A相连的城市有两个,即 A ---B 12 A---I 25
方法:Kruskal
Kruskal算法的思想是先把边按照权值进行排序,用贪心的思想优先选取权值较小的边,并依次连接,若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。
思路:用map把出现的字母转化成数字,就变成一道普通的最小生成树的题了。
代码如下:
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#define N 27
using namespace std;
int fi[N];
map<char,int>mp; //把出现的字母转化数字
struct node{
int u,v,w; //定义结构体,u,v两点构成一权值为w的边
}edge[100];
int Fin(int x)
{
if(x==fi[x]) //找根节点并返回跟节点的值
return x;
return fi[x]=Fin(fi[x]); //路径压缩
}
void Union(int a ,int b)
{
int fx=Fin(a);
int fy=Fin(b); //将a,b两点的根节点合并
if(fx!=fy)
fi[fx]=fy;
}
bool cmp (node a, node b)
{
return a.w<b.w; //把定义的结构体中的顺序按权值从小到大排
}
int main()
{ char s,e;
int n,t;
while(cin>>n&&n)
{ mp.clear(); //注意把mp清空
int tt=0;
int k=1;
for(int i=1;i<=n-1;i++)
{
cin>>s>>t;
if(mp[s]==0)
mp[s]=++tt;
for(int i=1;i<=t;i++)
{ int a;
cin>>e>>a;
if(mp[e]==0)
mp[e]=++tt;
edge[k].u=mp[s];
edge[k].v=mp[e];
edge[k++].w=a;
}
}
sort(edge+1,edge+k,cmp);
// for(int i=1;i<k;i++)
//cout<<edge[i].u<<" "<<edge[i].v<<" "<<edge[i].w<<endl; //用于查看排序后的
for(int i=1;i<=n;i++)
fi[i]=i; //初始化fi
int sum=0,num=0;
for(int i=1;i<k;i++)
{
int aa=Fin(edge[i].u),bb=Fin(edge[i].v);
if(aa!=bb)
{
Union(aa,bb);
sum+=edge[i].w;
num++;
}
if(num==n-1)
break;
}
//kruskal算法核心
cout<<sum<<endl;
}
return 0;
}