POJ 1258 最小生成树模版———Kruskal算法

输入图的邻接矩阵,求最小生成树的总权值(多组数据)

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值