输入包含的数据集个数在100以内,以0作为最后一行。每个数据集的第一行只包含一个表示村庄个数的数n,1<n<27,并且这n个村庄是由大写字母表里的前n个字母表示。接下来的n- 1行是由字母表的前n-1个字母开头。最后一个村庄表示的字母不用输入。对于每一行,以每个村庄表示的字母开头,然后后面跟着一个数字,表示有多少条道路可以从这个村到后面字母表中的村庄。如果k是大于0,表示该行后面会表示k条道路的k个数据。每条道路的数据是由表示连接到另一端村庄的字母和每月维修该道路的花费组成。维修费用是正整数的并且小于100。该行的所有数据字段分隔单一空白。该公路网将始终连接所有的村庄。该公路网将永远不会超过75条道路。没有任何一个村庄会有超过15条的道路连接到其他村庄(之前或之后的字母)。在下面的示例输入,其中第一个数据集是与上面的地图相一致的。
思路:最小生成树,以前还没做过,而且那时学长教的PPT没仔细看,只是大概看了一下,然后现在重新开始看,对prim算法了解了一点,对kruskal算法还不明白多少,努力中,这个代码还是参考别人的,正在学习最小生成树中……
prim算法代码如下:
#include<iostream> using namespace std; int n,a; int map[27][27],d[27]; int min(int a,int b) { return a<b?a:b; } void prim() { int i,j,now,min1,min2; now=1; a=0; for(i=1;i<n;i++) { d[now]=-1; min1=100000000; for(j=1;j<=n;j++) if(now!=j&&d[j]>=0) { d[j]=min(d[j],map[now][j]); if(d[j]<min1) { min1=d[j]; min2=j; } } now=min2; a+= min1; } cout<<a<<endl; } int main() { int i,j,num,m; char u,v; while(cin>>n&&n) { for(i=1;i<=n;i++) { d[i]=100000000; for(j=1;j<=n;j++) map[i][j]=100000000; } for(i=1;i<n;i++) { cin>>u>>num; while(num--) { cin>>v>>m; map[u-'A'+1][v-'A'+1]=m; map[v-'A'+1][u-'A'+1]=m; } } prim(); } return 0; }
kruskal算法代码如下:
#include<iostream> #include <algorithm> using namespace std; typedef struct //定义边(x,y),权即边长为w { int x,y; int w; }a; a e[27*27]; int rank[27],father[27],sum; //rank[x]表示x的秩 bool cmp(a p,a q) { return p.w<q.w; } int find(int x) //查找x元素所在的集合,回溯时压缩路径 { return father[x]==x?x:find(father[x]); } void un(int x,int y,int w) //合并x,y所在的集合,krustal算法因为即使边是最小的,若产生回路则不取,所以要合并集合,看看产不产生回路 { if(x==y) return; if(rank[x]>rank[y]) father[y]=x; //这其实是并查集的算法,因为回路问题,所以有了krustal算法,可以说是并查集的完美应用! else { if(rank[x]==rank[y]) rank[y]++; father[x]=y; } sum+=w; } int main() { int i,j,k,m,n,t; char c; while(cin>>m&&m) { for(i=0;i<m;i++) { father[i]=i; rank[i]=0; } for(i=0,k=0;i<m-1;i++) { cin>>c>>n; for(j=0;j<n;j++) { cin>>c>>e[k].w; e[k].x=i; e[k].y=c-'A'; k++; } } sort(e,e+k,cmp); sum=0; for(i=0;i<k;i++) un(find(e[i].x),find(e[i].y),e[i].w); cout<<sum<<endl; } return 0; }