还是畅通工程
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 44690 Accepted Submission(s): 20373
当N为0时,输入结束,该用例不被处理。
Statistic | Submit | Discuss | Note
kruskal算法图例:(摘自博客园最小生成树-Prim算法和Kruskal算法 - as_ - 博客园)
首先第一步,我们有一张图Graph,有若干点和边
将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择,排序完成后,我们率先选择了边AD。这样我们的图就变成了右图
在剩下的变中寻找。我们找到了CE。这里边的权重也是5
依次类推我们找到了6,7,7,即DF,AB,BE。
下面继续选择, BC或者EF尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB,BA,AD,DF来接连)。所以不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示了)。
本题为kruskal算法解决最小生成树基础练习题,将所有城镇间的连接保存到结构体,然后按照权值从小到大排序遍历,权值相加,直到最后连通为止。
附上AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100+5;
int N;
int par[maxn];
int sum;
struct edges{
int begin_,end_,val;
bool operator <(const edges a)
{
return val<a.val;
}
}edge[maxn*maxn];
void init()
{
for(int i=1;i<=N;i++)
par[i]=i;
sum=0;
}
int find(int a)
{
if(a==par[a])return a;
return par[a]=find(par[a]);
}
int kruskal(int cnt)
{
init();
for(int i=1;i<=cnt;i++)
{
int fx=find(edge[i].begin_);
int fy=find(edge[i].end_);
if(fx!=fy)
{
if(fx>fy)
par[fx]=fy;
else par[fy]=fx;
sum+=edge[i].val;
}
}
return sum;
}
int main()
{
while(~scanf("%d",&N),N)
{
int num=N*(N-1)/2;
for(int i=1;i<=num;i++)
scanf("%d%d%d",&edge[i].begin_,&edge[i].end_,&edge[i].val);
sort(edge+1,edge+num+1);
printf("%d\n",kruskal(num));
}
return 0;
}