畅通工程大集合(最小生成树)
畅通工程
Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100
Sample Output
3
?
///克鲁斯卡尔算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n,m,sum; struct node { int start; ///起点 int end; ///终点 int power; ///权值 } edge[5050]; int pre[5050]; int cmp(node a,node b) { return a.power<b.power; ///按权值排序 } int find( int x) ///并查集找祖先 { if (x!=pre[x]) ///递归法 { pre[x]=find(pre[x]); } return pre[x]; /*int a;///循环法 a=x; while(pre[a]!=a) { a=pre[a]; } return a;*/ } void merge( int x, int y, int n) { int fx =find(x); int fy =find(y); if (fx!=fy) { pre[fx]=fy; sum+=edge[n].power; } } int main() { int i,root; while ( scanf ( "%d%d" ,&m,&n)!=EOF) { if (m==0) { break ; } sum=0; for (i=1; i<=m; i++) { scanf ( "%d%d%d" ,&edge[i].start,&edge[i].end,&edge[i].power); } for (i=1; i<=m; i++) ///并查集的初始化 { pre[i]=i; } sort(edge+1,edge+m+1,cmp); for (i=1; i<=m; i++) { merge(edge[i].start,edge[i].end,i); } root=0; for (i=1; i<=n; i++) ///判断是否产生了生成树 { if (pre[i]==i) { root++; } if (root>1) ///如果根节点大于1说明没有产生最小生成树 { break ; } } if (root>1) { printf ( "?\n" ); } else { printf ( "%d\n" ,sum); } } return 0; } |
///普里姆算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #include<stdio.h> #include<string.h> #define MAX 0x3f3f3f3f using namespace std; int logo[1010]; ///用0和1来表示是否被选择过 int map1[1010][1010]; int dis[1010]; ///记录任意一点到这一点的最近的距离 int n,m; int prim() { int i,j,now; int sum=0; for (i=1;i<=n;i++) ///初始化 { dis[i]=MAX; logo[i]=0; } for (i=1;i<=n;i++) { dis[i]=map1[1][i]; } dis[1]=0; logo[1]=1; for (i=1;i<n;i++) ///循环查找 { now=MAX; int min1=MAX; for (j=1;j<=n;j++) { if (logo[j]==0&&dis[j]<min1) { now=j; min1=dis[j]; } } if (now==MAX) ///防止不成图 { break ; } logo[now]=1; sum=sum+min1; for (j=1;j<=n;j++) ///填入新点后更新最小距离 { if (logo[j]==0&&dis[j]>map1[now][j]) { dis[j]=map1[now][j]; } } } if (i<n) { printf ( "?\n" ); } else { printf ( "%d\n" ,sum); } } int main() { while ( scanf ( "%d%d" ,&m,&n)!=EOF) ///n是点数 { if (m==0) { break ; } memset (map1,0x3f3f3f3f, sizeof (map1)); ///map是邻接矩阵储存图的信息 for ( int i=0;i<m;i++) { int a,b,c; scanf ( "%d%d%d" ,&a,&b,&c); if (c<map1[a][b]) ///防止出现重边 { map1[a][b]=map1[b][a]=c; } } prim(); } return 0; } |
还是畅通工程
Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
Sample Output
3
5
Hint
Hint Huge input, scanf is recommended.
///克鲁斯卡尔算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n,m,sum; struct node { int start; ///起点 int end; ///终点 int power; ///权值 }edge[5050]; int pre[5050]; int cmp(node a,node b) { return a.power<b.power; ///按权值排序 } int find( int x) ///并查集找祖先 { if (x!=pre[x]) ///递归法 { pre[x]=find(pre[x]); } return pre[x]; /*int a;///循环法 a=x; while(pre[a]!=a) { a=pre[a]; } return a;*/ } void merge( int x, int y, int n) { int fx =find(x); int fy =find(y); if (fx!=fy) { pre[fx]=fy; sum+=edge[n].power; } } int main() { int i; while ( scanf ( "%d" ,&n)!=EOF) { if (n==0) { break ; } sum=0; m=n*(n-1)/2; //边数 for (i=1;i<=m;i++) { scanf ( "%d%d%d" ,&edge[i].start,&edge[i].end,&edge[i].power); } for (i=1;i<=m;i++) ///并查集的初始化 { pre[i]=i; ///每一个点的祖先都是自己 } sort(edge+1,edge+m+1,cmp); for (i=1;i<=m;i++) { merge(edge[i].start,edge[i].end,i); } printf ( "%d\n" ,sum); } return 0; } |
///普里姆算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #include<stdio.h> #include<string.h> #define MAX 0x3f3f3f3f using namespace std; int logo[1010]; ///用0和1来表示是否被选择过 int map1[1010][1010]; int dis[1010]; ///记录任意一点到这一点的最近的距离 int n,m; int prim() { int i,j,now; int sum=0; for (i=1; i<=n; i++) ///初始化 { dis[i]=MAX; logo[i]=0; } for (i=1; i<=n; i++) ///任意一个点到第一个点的距离 { dis[i]=map1[1][i]; } dis[1]=0; logo[1]=1; ///第一个点已经被访问过,加入可选顶点集 for (i=1; i<n; i++) { now=MAX; int min1=MAX; for (j=1; j<=n; j++) ///再找到一条以可选顶点集里为顶点的一条边 { if (logo[j]==0&&dis[j]<min1) { now=j; min1=dis[j]; } ///循环查找最小值 } if (now==MAX) ///防止不成图 { break ; } logo[now]=1; sum=sum+min1; for (j=1; j<=n; j++) ///填入新点后更新最小距离,剩余各点到可选顶点集的距离 { if (logo[j]==0&&dis[j]>map1[now][j]) { dis[j]=map1[now][j]; } } } printf ( "%d\n" ,sum); } int main() { while ( scanf ( "%d" ,&n)!=EOF) ///n是点数 { if (n==0) { break ; } m=n*(n-1)/2l; memset (map1,0x3f3f3f3f, sizeof (map1)); ///map是邻接矩阵储存图的信息 for ( int i=0; i<m; i++) { int a,b,c; scanf ( "%d%d%d" ,&a,&b,&c); if (c<map1[a][b]) ///防止出现重边 { map1[a][b]=map1[b][a]=c; } } prim(); } return 0; } |
继续畅通工程
Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
当N为0时输入结束。
Output
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
Sample Input
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
Sample Output
3
1
0
///克鲁斯卡尔算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n,m,sum; struct node { int start; ///起点 int end; ///终点 int power; ///权值 }edge[5050]; int pre[5050]; int cmp(node a,node b) { return a.power<b.power; ///按权值排序 } int find( int x) ///并查集找祖先 { if (x!=pre[x]) ///递归法 { pre[x]=find(pre[x]); } return pre[x]; /*int a;///循环法 a=x; while(pre[a]!=a) { a=pre[a]; } return a;*/ } void merge( int x, int y, int n) { int fx =find(x); int fy =find(y); if (fx!=fy) { pre[fx]=fy; sum+=edge[n].power; } } int main() { int i,flag; while ( scanf ( "%d" ,&n)!=EOF) { if (n==0) { break ; } sum=0; m=n*(n-1)/2; for (i=1;i<=m;i++) { scanf ( "%d%d%d%d" ,&edge[i].start,&edge[i].end,&edge[i].power,&flag); if (flag==1) { edge[i].power=0; ///已经修好的公路的成本更新为0; } } for (i=1;i<=m;i++) ///并查集的初始化 { pre[i]=i; } sort(edge+1,edge+m+1,cmp); for (i=1;i<=m;i++) { merge(edge[i].start,edge[i].end,i); } printf ( "%d\n" ,sum); } return 0; } |
///普里姆算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #include<stdio.h> #include<string.h> #define MAX 0x3f3f3f3f using namespace std; int logo[1010]; ///用0和1来表示是否被选择过 int map1[1010][1010]; int dis[1010]; ///记录任意一点到这一点的最近的距离 int n,m; int prim() { int i,j,now; int sum=0; for (i=1; i<=n; i++) ///初始化 { dis[i]=MAX; logo[i]=0; } for (i=1; i<=n; i++) ///任意一个点到第一个点的距离 { dis[i]=map1[1][i]; } dis[1]=0; logo[1]=1; ///第一个点已经被访问过,加入可选顶点集 for (i=1; i<n; i++) { now=MAX; int min1=MAX; for (j=1; j<=n; j++) ///再找到一条以可选顶点集里为顶点的一条边 { if (logo[j]==0&&dis[j]<min1) { now=j; min1=dis[j]; } ///循环查找最小值 } if (now==MAX) ///防止不成图 { break ; } logo[now]=1; sum=sum+min1; for (j=1; j<=n; j++) ///填入新点后更新最小距离,剩余各点到可选顶点集的距离 { if (logo[j]==0&&dis[j]>map1[now][j]) { dis[j]=map1[now][j]; } } } printf ( "%d\n" ,sum); } int main() { int flag; while ( scanf ( "%d" ,&n)!=EOF) ///n是点数 { if (n==0) { break ; } m=n*(n-1)/2l; memset (map1,0x3f3f3f3f, sizeof (map1)); ///map是邻接矩阵储存图的信息 for ( int i=0; i<m; i++) { int a,b,c; scanf ( "%d%d%d%d" ,&a,&b,&c,&flag); if (!flag) { map1[a][b]=map1[b][a]=c; } else { map1[b][a]=map1[a][b]=0; ///已将连接的两个点之间的距离换成0 } } prim(); } return 0; } |
本文作者:王陸
本文链接:https://www.cnblogs.com/wkfvawl/p/9239135.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步