NYOJ 38 布线问题 prim && Kruskral 模板题

来源:互联网 发布:java license 框架 编辑:程序博客网 时间:2024/05/16 09:14

1.prim算法

1.将第一个点放入最小生成树的集合中(标记visit[i]=1意思就是最小生成树集合)。

2.从第二个点开始,初始化lowcost[i]为跟1点相连(仅仅相连)的边的权值(lowcost[i]不是这个点的最小权值!在以后会逐步更新)。

3.找最小权值的边。

从第二点开始遍历,如果不是最小生成树的集合的点,则找出从2到n的最小权值(lowcost[j])。

4.将找出来的最小权值的边的顶点加入最小生成树的集合中(标记visit[i] = 1),权值相加。

5.更新lowcost[j]集合。

假设第一次:lowcost[2]代表与1相连的点的权值,现在加入了k点。则比较k点与2点的边map[k][2]和lowcost[2]的大小,若lowcost[2]大,则lowcost[2] = map[k][2]。(关键步骤:实质就是每在最小生成树集合中加入一个点就需要把这个点与集合外的点比较,不断的寻找两个集合之间最小的边)

6.循环上述步骤,指导将全部顶点加入到最小生成树集合为止。

#include<iostream>#include<string>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;int map[510][510], lowcost[510];bool visit[510];int num, sum;void prime(){int temp, k;sum = 0;visit[1] = 1;for(int i = 2; i <= num; ++i) //初始化lowcost[i] = map[1][i];for(int i = 2; i <= num; ++i) //找最小权值{temp = 0x0fffffff;for(int j = 2; j <= num; ++j){if(!visit[j] && temp > lowcost[j]){temp = lowcost[j];k = j;}}visit[k] = 1; //加入最小生成树集合sum += temp;for(int j = 2; j <= num; ++j) //更新lowcost[j]if(lowcost[j] > map[k][j] && !visit[j])lowcost[j] = map[k][j];}}int main(){int ncase, cost, x, y, z, minn, tmp;scanf("%d", &ncase);while(ncase--){memset(map, 0, sizeof(map));memset(lowcost, 0, sizeof(lowcost));memset(visit, 0, sizeof(visit));scanf("%d%d", &num, &cost);for(int i = 1; i <= cost; ++i) //输入边和权值{scanf("%d%d%d", &x, &y, &z);map[x][y] = map[y][x] = z;}minn = 0x0fffffff;for(int i = 1; i <= num; ++i){scanf("%d", &tmp);if(minn > tmp)minn = tmp;}prime();printf("%d\n", sum + minn);}return 0;}

2、kruskal

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<algorithm>using namespace std;int pri[510];typedef struct Kruskal{int a;int b;int value;};bool cmp(const Kruskal &a, const Kruskal &b) //权值排序{return a.value < b.value;}int unionsearch(int x) //查找根结点+路径压缩{return x == pri[x] ? x : unionsearch(pri[x]);}int main(){int ncase, v, e, sum, minn, tmp;Kruskal edge[125000];scanf("%d", &ncase);while(ncase--){sum = 0;memset(edge, 0, sizeof(edge));scanf("%d%d", &v, &e);for(int i = 1; i <= v; ++i) //初始化pri[i] = i;for(int i = 1; i <= e; ++i)scanf("%d%d%d", &edge[i].a, &edge[i].b, &edge[i].value);sort(edge + 1, edge + 1 + e, cmp); //按权值从小到大排序minn = 0x0fffffff;for(int i = 1; i <= v; ++i){scanf("%d", &tmp);if(minn > tmp)minn = tmp;}for(int i = 1; i <= e; ++i){int root1, root2;root1 = unionsearch(edge[i].a);root2 = unionsearch(edge[i].b);if(root1 == root2) //为环continue;pri[root1] = root2; //合并sum += edge[i].value; //权值相加}printf("%d\n", sum + minn);}return 0;}



0 0