[ACM] hud 还是畅通工程(重写)
还是畅通工程
Problem 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 5Huge input, scanf is recommended.HintHint
Source
Recommend
这题本质是求最小生成树,其中用到了并查集。这题以前做过,那时候是一次AC的,今天重写一次,错误百出,改了好久(详见代码注释),通过这次重写,对最小生成树的执行过程有了巩固和提高,对并查集的使用也有了一定的理解。
代码:
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; int parent[102],n; struct Node { int s,e,len; }node[5002]; bool cmp(Node a,Node b) { if(a.len<b.len) return true; return false; } void init(int n) { for(int i=1;i<=n;i++) parent[i]=i;//犯得第一个错误,一开始写成parent[i]=0;初始化,每个村庄的根节点应该是自己的编号 } int find(int x) { return parent[x]==x?x:find(parent[x]); } void unite(int x,int y) { x=find(x); y=find(y); if(x==y) return ; else parent[x]=y; } bool unsame(int x,int y) { if(find(x)==find(y)) return false;//犯得第三个错误,当两个村庄没有共同根节点时才相加其len return true; } int main() { while(cin>>n&&n) { int m=n*(n-1)/2; init(n);//犯得第四个错误,初始化是对村庄的编号进行初始化,n应该是村庄的个数,而不是路的个数。 int length=0; for(int i=1;i<=m;i++) scanf("%d%d%d",&node[i].s,&node[i].e,&node[i].len); sort(node+1,node+1+m,cmp);//犯得第二个错误,对节点的个数排序,千万注意这里的节点不是村庄还是村庄之间的路。 for(int i=1;i<=m;i++) { //第一种解法 //if(unsame(node[i].s,node[i].e)) // length+=node[i].len; //unite(node[i].s,node[i].e); //犯得第五个错误,把unie写在了前面,如果那样,先连接村庄,下一句判断那么两个村庄必定有相同的根节点(二者之一),造成length+=node[i].len;每次循环都执行,必定错误。 //第二种解法 int a=find(node[i].s); int b=find(node[i].e); if(a==b) continue; parent[a]=b; length+=node[i].len; } cout<<length<<endl; } return 0; }