题目描述 Description
农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了使花费最少,他想铺设最短的光纤去连接所有的农场。 你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。 每两个农场间的距离不会超过100000
输入描述 Input Description
第一行: 农场的个数,N(3<=N<=100)。
第二行..结尾: 接下来的行包含了一个N*N的矩阵,表示每个农场之间的距离。理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们每行限制在80个字符以内,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为线路从第i个农场到它本身的距离在本题中没有意义。
输出描述 Output Description
只有一个输出,是连接到每个农场的光纤的最小长度和。
样例输入 Sample Input
类型:图论 难度:1.54
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
题意:给出图的邻接矩阵,求最小生成树
分析:比较清晰的基本题,这里我用kruskal算法,将图中所有边按长度排序,从小到大选择, 如边的两点尚未连通,则将边加入,记录结果。
注意:判断两个点是否已经连通的方法,用f[i]记录i所在连通分支形成的树的父亲,初始化f[i]=i。若将i,j两个连通分支合并,则令f[f[i]] = f[f[j]],每次通过f数组找到i,j所在连通分支的根节点,若相同,则i,j连通,否则不连通。
优化:上述方法很可能造成连通分支形成的树为退化树(每个节点只有一个子节点,退化为单链表),而上述问题实际上是一个合并等价类的问题,数据结构书中有union和find的优化操作,写的很清楚,这里就不赘述了。
代码:
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int n;
struct node
{
int len,x,y;
bool operator < (node b) const
{
return len > b.len;
}
bool operator > (node b) const
{
return len < b.len;
}
bool operator == (node b) const
{
return len == b.len;
}
};
priority_queue<node> qu;
int f[110];
int find(int x)
{
return f[x]==x ? x: find(f[x]);
}
int main()
{
cin>>n;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
{
int len;
cin>>len;
if(!len) continue;
node now;
now.len = len;
now.x = i;
now.y = j;
qu.push(now);
}
for(int i=0; i<n; i++)
f[i] = i;
int ans = 0,cnt = 1;
while(cnt<n)
{
node now = qu.top();
qu.pop();
int xc = find(now.x);
int yc = find(now.y);
if(xc == yc)
continue;
ans += now.len;
cnt++;
f[xc] = yc;
}
cout<<ans<<endl;
}