(最小生成树问题:Prim,Kruskal)村村通公路
2017-08-21 17:51
351 查看
3362数据结构实验之图论六:村村通公路
Problem Description
当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。
Input
连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <=
3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。
Output
输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。
Example Input
Example Output
解题思路
构造最小生成树的算法有普里姆算法(Prim)和克鲁斯卡尔算法(Kruskal)
1.普里姆算法(Prim):归并顶点(加顶点法),与边数无关,适于稠密图;
2.克鲁斯卡尔算法(Kruskal):归并边(加边法),适于稀疏图。实现过程借助并查集。
并查集知识补充如下。
并查集详解
代码1:普里姆算法(Prim)
代码2:克鲁斯卡尔算法(Kruskal)
利用qsort()排序。
Problem Description
当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。
Input
连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <=
3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。
Output
输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。
Example Input
5 8 1 2 12 1 3 9 1 4 11 1 5 3 2 3 6 2 4 9 3 4 4 4 5 6
Example Output
19
解题思路
构造最小生成树的算法有普里姆算法(Prim)和克鲁斯卡尔算法(Kruskal)
1.普里姆算法(Prim):归并顶点(加顶点法),与边数无关,适于稠密图;
2.克鲁斯卡尔算法(Kruskal):归并边(加边法),适于稀疏图。实现过程借助并查集。
并查集知识补充如下。
并查集详解
代码1:普里姆算法(Prim)
/*普利姆算法(加点法): 邻接矩阵储存 在一定范围内,找到距离最短。 从村庄1开始,寻找与村庄1连通的有最小权值的村庄,之后再从该村庄找下一个有最小权值的村庄。*/ #include<stdio.h> #include<string.h> #define INF 2147483647 //表示村庄之间不连接 int vis[10000]; /*vis 访问标志数组 ——记录其他村庄集合 与已选的村庄集合哪个的成本最低。*/ int dis[101][101]; /*dis 存储相邻两村庄的权值。* 4000 / int lowc[10000]; /*lowc 记录其他村庄集合与已选的村庄集合的最低的成本*/ int prime(int cost[][101],int n) //普利姆 cost数组存储着dis数组数据 { int i,j,p; //p用来记录每一次循环找到的节点的编号 int minc,res=0; memset(vis,0,sizeof(vis)); //vis数组初始化为0 for(i=1;i<=n;i++) //记录从村庄1(1 2 3 4 5)到村庄n的最低成本 { lowc[i]=cost[1][i];//我们从1号节点开始生成树 } vis[1]=1; //对生成的树根标记访问 for(i=1;i<n;i++) //要生成n-1条边,所以循环n-1次 { minc=INF; //p=-1; for(j=1;j<=n;j++) { if(!vis[j]&&lowc[j]<minc) //遍历找到村庄1(1 2 3 4 5)到其他村庄的最低成本 { minc=lowc[j]; p=j; //p记录下一个村庄代替当前村庄 } } if(INF==minc)//如果在此跳出循环,表示有城市之间不能连通 return -1; //此图不连通 res+=minc;//加上找到的最小权值 vis[p]=1; //标记找到的该节点被访问 for(j=1;j<=n;j++) //更新lowc数组 { if(vis[j]==0&&lowc[j]>cost[p][j]) { lowc[j]=cost[p][j];//如果该点还没有被访问过, //更新生成树到该点的距离; } } } return res; } int main() { int m,n,i,j,x,y,w; while(scanf("%d %d",&n,&m)!=EOF) //输入村落数目n和道路数目m 多组输入 { for(i=1;i<=n;i++) //初始化dis数组,若是同一村落为0,不是先设为最大 { for(j=1;j<=n;j++) { if(j==i) { dis[i][j]=0; } else { dis[i][j]=INF; } } } for(i=0;i<m;i++) { scanf("%d %d %d",&x,&y,&w); //依次输入村庄编号和预算成本 if(dis[x][y]>w) { dis[x][y]=w; //无向图,预算成本赋值 dis[y][x]=w; } } printf("%d\n",prime(dis,n)); //调用prime } }
代码2:克鲁斯卡尔算法(Kruskal)
#include<cstdio> #include<stdlib.h> #include<algorithm> using namespace std; int parent[1001]; typedef struct Node{ int u,v,info; }Node; Node cla[3001]; int cost; /*int fnd(int t) { if(t!=parent[t]) return fnd(parent[t]); return t; }*/ int fnd(int t) { int r=t; while(parent[r]!=r) r=parent[r]; int i=t,j; while(i!=r)//压缩路径 { j=parent[i]; parent[i]=r; i=j; } return r; } void Kruskal(Node s) { int fx=fnd(s.u); int fy=fnd(s.v); if(fx!=fy) { parent[fx]=fy; cost+=s.info; //printf("fx=%d,fy=%d,cost=%d\n",fx,fy,cost); } } bool cmp(Node A,Node B) { return A.info<B.info; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { int i,cnt=0; cost=0; for(i=1;i<=n;i++) { parent[i]=i; } for(i=0;i<m;i++) { scanf("%d%d%d",&cla[i].u,&cla[i].v,&cla[i].info); } sort(cla,cla+m,cmp); for(i=0;i<m;i++) { Kruskal(cla[i]); } for(i=1;i<=n;i++) { if(parent[i]==i) cnt++; } if(cnt!=1) printf("-1\n"); else printf("%d\n",cost); } return 0; }
利用qsort()排序。
#include<cstdio> #include<stdlib.h> using namespace std; int parent[1001]; typedef struct Node{ int u,v,info; }Node; Node cla[3001]; int cost; int fnd(int t) { int r=t; while(parent[r]!=r) r=parent[r]; int i=t,j; while(i!=r)//压缩路径 { j=parent[i]; parent[i]=r; i=j; } return r; } void Kruskal(Node s) { int fx=fnd(s.u); int fy=fnd(s.v); if(fx!=fy) { parent[fx]=fy; cost+=s.info; // printf("fx=%d,fy=%d,cost=%d\n",fx,fy,cost); } } int cmp(const void *a,const void *b) //按村庄之间的预算成本从小到大排序 { return (*(Node *)a).info>(*(Node *)b).info?1:-1; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { int i,cnt=0; cost=0; for(i=1;i<=n;i++) { parent[i]=i; } for(i=0;i<m;i++) { scanf("%d%d%d",&cla[i].u,&cla[i].v,&cla[i].info); } qsort(cla,m,sizeof(cla[0]),cmp); //qsort排序 /*1 待排序数组首地址 2 数组中待排序元素数量 3 各元素的占用空间大小 4 指向函数的指针,用于确定排序的顺序*/ for(i=0;i<m;i++) { Kruskal(cla[i]); } for(i=1;i<=n;i++) { if(parent[i]==i) cnt++; } if(cnt!=1) printf("-1\n"); else printf("%d\n",cost); } return 0; }
相关文章推荐
- NYOJ 38 布线问题 最小生成树 prim与Kruskal
- Prim && Kruskal 生成MST(最小生成树)及最短路径问题
- hdoj 1875 畅通工程再续【最小生成树 kruskal && prim】
- hdu1301 prim和kruskal求最小生成树
- hdoj 1863 畅通工程【最小生成树 kruskal && prim】
- 最小生成树-Prim及Kruskal
- 【算法复习】图的最小生成树(Prim&Kruskal)
- POJ1287 Networking(最小生成树,Kruskal,Prim)
- HDU 1879 最小生成树 prim + kruskal
- 最小生成树两种算法。kruskal和prim
- Prim和Kruskal最小生成树
- 最小生成树之 prim & kruskal
- HDOJ 1301 Jungle Roads 最小生成树 kruskal && prim
- POJ2349—最小生成树的Kruskal和Prim实现
- hdu 1233 还是畅通工程(最小生成树,prim,kruskal)
- poj1861 最小生成树 prim & kruskal
- hdu 1233 还是畅通工程 (最小生成树,prim,优先队列,kruskal并查集)
- Kruskal & Prim 最小生成树HDU1863 畅通工程
- 最小生成树算法Prim、Kruskal
- 最小生成树Prim和kruskal