[HDU] 1879 继续畅通工程-使用kruskal算法,用到并查集
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1879
方法:在接收输入的时候,如果两个地方已经存在道路,则将道路上的点加入到并查集,同时,该边在后期计算最小生成树时,不予考虑。不予考虑的方式就是不把该边纪录在邻接矩阵里面。而道路还没有修建的两个点,在考虑的时候是只把该两点间的最小修建费用作为权值的边纪录在邻接矩阵里面。然后把矩阵中的边排序,准备开始调用kruskal算法。在调用该算法往集合添加轻边的时候,要考虑该边的两个端点是否已经因为前面添加的轻边而已经在生成树里,这个时候用到并查集。由于之前已经添加已修建的道路的两个顶点在并查集中,所以该两点的边不在往生成树里添加,即使边的权值更小,或即使还有更小的边可以取代它。因为它是已经建立好了的。
View Code
#include<iostream> #include<algorithm> using namespace std; struct ArcNode { int x; int y; int cost; }; bool compare(ArcNode a,ArcNode b) { return a.cost<b.cost; } int px[100]; int rank[100]; int findSet(int x) { int p=x; while(x!=px[x]) x=px[x]; int z=p; while(z!=x) { p=px[z]; px[z]=x; z=p; } return x; } bool merge(int x, int y) { int setx=findSet(x); int sety=findSet(y); if(setx==sety) { return false; } else { if(rank[setx]>rank[sety]) px[sety]=setx; else { px[setx]=sety; if(rank[setx]==rank[sety]) rank[sety]++; } return true; } } int main() { int nodeCount = 0; int matrix[100][100]; ArcNode roads[5000];//注意 边数很可能比点数多 while(scanf("%d",&nodeCount) && nodeCount!=0) { for(int k=1;k<=nodeCount;k++) { px[k] = k; rank[k]=0; for(int w=1;w<=nodeCount;w++) matrix[k][w] = -1; } int i =0,source,destiny,cost,isBuilt,index=0; while(i<(nodeCount*(nodeCount-1)/2)) { scanf("%d %d %d %d",&source,&destiny,&cost,&isBuilt); if(isBuilt == 0) { if(matrix[source][destiny] == -1 || matrix[source][destiny] > cost ) matrix[source][destiny] = cost; } else { merge(source,destiny); } i++; } for(int k=1;k<=nodeCount;k++) { for(int w=1;w<=nodeCount;w++) if(matrix[k][w]!=-1) { ArcNode node; node.x=k; node.y=w; node.cost=matrix[k][w]; roads[index]=node; index++; } } sort(roads,roads+index,compare); int sum = 0; for(int x=0;x<index;x++) { ArcNode t_node = roads[x]; if(merge(t_node.x,t_node.y)) { sum+=t_node.cost; } } cout<<sum<<endl; } return 0; }