还是畅通工程
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
很明显就是最小生成树。说一下kruskal算法:3 5
1).记Graph中有v个顶点,e个边
2).新建图G,G中拥有原图中相同的e个顶点,但没有边
3).将原图Graph中所有e个边按权值从小到大排序
4).循环:从权值最小的边开始遍历每条边,如果边连接的两顶点不在同一连通分量中,则加入这条边;否则不加。直至图Graph中所有的节点都在同一个连通分量中
当然还有一种prim算法:
1)一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
就这道题而言,prim算法比kruskal算法稍快一点。
当然算法的选取还是看题啦:稠密图用prim算法,稀疏图用kruskal算法。
kruskal代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int N, ans, flag[110]; //最小生成树kruskal算法 struct ss { int a, b, len; } f[5100]; bool cmp(ss x, ss y) { if(x.len < y.len) return true; else return false; } int fi(int z) { if(flag[z] == z) return z; else return flag[z] = fi(flag[z]);//路径压缩 } int main() { while(scanf("%d", &N) && N) { ans = 0; int m = N*(N-1)/2; for(int i = 0;i <= N; ++i) flag[i] = i; for(int i = 0;i < m; ++i) scanf("%d %d %d", &f[i].a, &f[i].b, &f[i].len); sort(f, f+m, cmp); for(int i = 0;i < m; ++i) { int x = fi(f[i].a); int y = fi(f[i].b); if(x != y)//不连通就将其连通起来 { flag[x] = y; ans += f[i].len;//求和 } } cout << ans << endl; } return 0; }
prim算法如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define MAXN 99999999; const int maxn = 110; int Map[maxn][maxn], l[maxn], flag[maxn]; int N, M, fr, to, pos, len, ans, minlen; int main() { while(scanf("%d", &N) && N) { //初始化 ans = 0; minlen = MAXN; memset(flag, 0, sizeof(flag)); memset(Map, 0, sizeof(Map)); M = N*(N-1)/2; for(int i = 0;i <= N; ++i) l[i] = MAXN; //输入 for(int i = 0;i < M; ++i) { scanf("%d %d %d", &fr, &to, &len); Map[fr][to] = len; Map[to][fr] = len; } //prim算法 flag[1] = 1;//默认从节点1开始 for(int i = 1;i <= N; ++i) l[i] = Map[1][i];//初始化 for(int i = 1;i < N; ++i) { minlen = 1 << 30; for(int j = 1;j <= N; ++j)//找出最近到达的下一节点 { if(!flag[j] && l[j] < minlen) { minlen = l[j]; pos = j;//记录下一节点 } } flag[pos] = 1;//标记 ans += l[pos];//求和 for(int j = 1;j <=N; ++j)//更新权值 { if(!flag[j] && l[j] > Map[pos][j] && Map[pos][j]) { l[j] = Map[pos][j]; } } } cout << ans << endl; } return 0; }