[HDU-1233]还是畅通工程

并查集 最小生成树

还是畅通工程

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 61943 Accepted Submission(s): 28107

Problem Description

某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

Input

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当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
5

Hint

Huge input, scanf is recommended.

代码
没什么好说的,这是需要算加权边了的,然后Kruskal算法本质感觉就是个贪心算法。。
AC 202ms G++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
最小生成树Kruskal算法
*/
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=100;
int pre[maxn+3];
struct Node
{
int st,to;
int w;
}edge[maxn*(maxn-1)/2+3];
bool cmp(Node a,Node b)
{
return a.w<b.w;
}
void init(int n)
{
for (int i=1;i<=n;i++) pre[i]=i;//初始化,刚开始为自己
}
int unionfind(int x)//查找根节点
{
int r=x;
while (pre[r]!=r)
{
r=pre[r];
}
int i=x,j;
while (pre[i]!=r)//路径压缩。最好直接连接根节点
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
int unionjoin(int x,int y)//检查2个点的根节点是否是同一个,是就不需要任何操作,不是就将他们的根节点1加入根节点2
{
int fx=unionfind(x),fy=unionfind(y);
if (fx!=fy)
{
pre[fx]=fy;
return 1;
}
return 0;
}
int kruskal(int n,int m)//每次找边最短的,并判断是不是在同一棵树内,是就略过,不是就加进答案,生成这条边
{
int num=n-1;
int ans=0;
for (int i=1;i<=m;i++)
{
if (unionjoin(edge[i].st,edge[i].to))
{
ans+=edge[i].w;
num--;
}
if (!num)//当有n-1条边时退出
{
break;
}
}
return ans;
}
int main()
{
int n,m,a,b,c,res;
while(~scanf("%d",&n)&&n)
{
init(n);
res=0;
m=n*(n-1)/2;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
edge[i].st=a;
edge[i].to=b;
edge[i].w=c;
}
sort(edge+1,edge+m+1,cmp);
res=kruskal(n,m);
printf("%d\n",res);
}
}