原题链接:点击此处
题目大意在相通n个岛屿的所有桥都坏了,要重修,重修每一个桥所用的时间不同,求重修使每个岛屿都间接或直接与其他岛屿相同时所用的的最短时间(只有修完一个桥后才可修下一个桥)。简言之就是求最小生成树。
对于数据,数据输入的第一行n代表岛屿的个数,当为0是结束程序,接着n-1行开始时为这岛屿的编号,用大写字母表示,接着是一个整数m,表示与该岛屿连接的字典序大于该岛屿编号的个数,然后该行输入m对数据,每对数据的第一个字母表示与该岛屿连通的岛屿的编号,第二个数字表示要重修两岛屿之间桥所需要的时间,输出数据见样例及原题。
利用并查集来判断是否连通,紧接着利用Kruskal算法。
Kruskal算法的基本思想:
假设WN=(V,{E})是一个含有n个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:
先构造一个只含n个顶点,而边集为空的子图,
若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有n棵树的一个森林。
之后,从网的边集E中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,
也就是说,将这两个顶点分别所在的两棵树合成一棵树;
反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。
依次类推,直至森林中只有一棵树,也即子图中含有n-1条边为止。
代码如下:
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int pre[27]; const int inf = ( 1 << 20 ) ; struct prog { int u; int v; int w; }Map[80];//存储边的信息,包括起点/终点/权值 bool cmp ( prog a , prog b) {//排序函数,将边根据权值从小到大排 return a.w<b.w; } int Find(int x) { if(x!=pre[x]) pre[x]=Find(pre[x]); return pre[x]; } int main() { int n; while(scanf("%d",&n)&&n) { for(int i=0;i<27;i++) pre[i]=i; int k=0; for ( int i = 0 ; i < n - 1 ; i ++ ) { //构造边的信息 char str[3]; int m; scanf("%s%d",str,&m); for(int i=0;i<m;i++,k++) { char str2[3]; int t; cin >> str2 >> t ; Map[k].u=(str[0]-‘A‘); Map[k].v=(str2[0]-‘A‘); Map[k].w=t; } } sort ( Map ,Map + k , cmp );//将边从小到大排序 int ans=0; //所要求的答案 for (int i = 0 ; i < k ; i ++ ) { int x = Find(Map[i].u); int y = Find(Map[i].v); if( x!=y) {//如果两点不在同一连通分量里,则将两点连接,并存储该边 ans+=Map[i].w; pre[x]=y; } } printf("%d\n",ans); } return 0; }
原文:http://www.cnblogs.com/gdvxfgv/p/5721837.html