输入图的邻接矩阵,求最小生成树的总权值(多组数据)
Input
The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.
Output
For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.
Sample Input
4 0 4 9 21 4 0 8 17 9 8 0 16 21 17 16 0
Sample Output
28
1.Kruskal算法:
将图G中的边按权值从小到大依次选取(排序函数——sort()),若选取的边使生成树不形成回路,则把它并入TE中,若形成回路则将其舍弃,直到TE中包含n-1条边为止,此时T为最小生成树。Kruskal算法就是加边,找最小权值的加入。
2.关键问题:如何判断欲加入的一条边是否与生成树中边构成回路?——并查集
将各顶点划分为所属集合的方法来解决,每个集合的表示一个无回路的子集。开始时边集为空,N个顶点分属N个集合,每个集合只有一个顶点,表示顶点之间互不连通。
当从边集中按顺序选取一条边时,若它的两个端点分属于不同的集合,则表明此边连通了两个不同的部分,因每个部分连通无回路,故连通后仍不会产生回路,此边保留,同时把相应两个集合合并
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
struct Edges
{
int i;
int j;
int w;
bool operator<(const Edges &e)const
{
return w<e.w;
}
Edges(int ii,int jj,int ww):i(ii),j(jj),w(ww){}
Edges(){}
};
vector<Edges>edges;
vector<int>par;
int getRoot(int root)
{
if(par[root]!=root)
par[root]=getRoot(par[root]);
return par[root];
}
void Merge(int x,int y)
{
int fx=getRoot(x);
int fy=getRoot(y);
if(fx!=fy)
{
par[fy]=fx;
}
}
int main()
{
int n;
while(cin>>n){
par.clear();
edges.clear();
for(int i=0;i<n;i++)
par.push_back(i);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
int w;
scanf("%d",&w);
edges.push_back(Edges(i,j,w));
}
}
int ans=0;
int cnt=0;
sort(edges.begin(),edges.end());
for(int k=0;k<edges.size();k++)
{
if(getRoot(edges[k].i)!=getRoot(edges[k].j))
{
Merge(edges[k].i,edges[k].j);
cnt++;
ans=ans+edges[k].w;
}
if(cnt==n-1) break;
}
cout<<ans<<endl;
}
return 0;
}