跟前几道畅通工程的题一样,都是用Kruskal算法求最小生成树,唯一的区别是要处理已经修建好的道路 ,我的方法是如果检测到一个道路已经建好,就将他的花费置为0。然后就是常规并查集+Kruskal了
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int MAXN = 110; int father[MAXN]; int height[MAXN]; struct Edge{ int from; int to; int length; int tag; }; Edge edge[5000]; void Initial(int n)//并查集初始化 { for(int i = 0; i <= n; i++) { father[i] = i; height[i] = 0; } return; } int Find(int x)//并查集查找根节点 { if(x != father[x]) { father[x] = Find(father[x]); } return father[x]; } void Union(int x, int y)//不属于一个集合的元素合并 { x = Find(x); y = Find(y); if(x != y) { if(height[x] < height[y]) { father[x] = y; } else if(height[x] > height[y]) { father[y] = x; } else { father[y] = x; height[x]++; } } return; } bool Compare(Edge x, Edge y) { return x.length < y.length; } int Kruskal(int n, int edgelength)//Kruskal算法求最小生成树 { Initial(n); int cost = 0; for(int i = 0; i < edgelength; i++) { int x = edge[i].from; int y = edge[i].to; if(Find(x) != Find(y)) { Union(x, y); cost += edge[i].length; } } return cost; } int main() { int n; while(scanf("%d", &n) != EOF)//顶点数 { if(n == 0) break; int edgelength = n * (n - 1) / 2;//边数 for(int i = 0; i < edgelength; i++) { scanf("%d%d%d%d", &edge[i].from, &edge[i].to, &edge[i].length, &edge[i].tag); if(edge[i].tag == 1)//如果道路已建,花费置为0 { edge[i].length = 0; } } sort(edge, edge + edgelength, Compare);//将边集按权值从小到大排序 int cost = Kruskal(n, edgelength);//通过Kruskal算法求得最小生成树权值之和即为结果 printf("%d\n", cost); } return 0; }