POJ 1258 最小生成树模版———prim算法 (prioirty_queue实现 Prim + 堆 完成)

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

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.prim算法:

      首先从V中任取一个顶点(假定取v1),将它并入U中,此时U={v1},然后只要U是V的真子集(U∈V),就从那些一个端点已在T中,另一个端点仍在T外的所有边中,找一条最短边,设为(vi,vj),其中vi∈U,vj ∈V-U,并把该边(vi, vj)和顶点vj分别并入T的边集TE和顶点集U,如此进行下去,每次往生成树里并入一个顶点和一条边,直到n-1次后得到最小生成树。

2.关键问题: 每次如何从连接T中和T外顶点的所有边中,找到一条最短的?
2.1 如果用邻接矩阵存放图,而且选取最短边的时候遍历所有点进行选取,则总时间复杂度为O(V2), V 为顶点个数
2.2 用邻接表存放图,并使用堆来选取最短边,则总时间复杂度为O(ElogV)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring> 
#include<vector>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
int n;
struct Edges
{
	int v;
	int w;
	bool operator<(const Edges &e)const
	{
		return w>e.w;
	}
	Edges(int vv,int ww):v(vv),w(ww){}
	Edges(){}
	
};
 vector<vector<Edges> >g(110);//二维 
int prim(vector<vector<Edges> > &g,int n)
{
	Edges e(0,0);
	priority_queue<Edges>q;//用优先队列,就可以取得当前权值最小的点,利于后面的判断 
	q.push(e);
	vector<int>vis(n);
	vector<int>dis(n);
	for(int i=0;i<n;i++)
	{
		vis[i]=0;
		dis[i]=inf;
	}
	int sum=0;//求权值之和 
	int cnt=0;//计数,是否联通 
	while(cnt<n&&!q.empty())
	{
		do
		{
		  e=q.top();
		  q.pop();
		}while(vis[e.v]==1&&!q.empty());
		if(vis[e.v]==0)
		{
			cnt++;
			vis[e.v]=1;
			sum=sum+e.w;
			for(int i=0;i<g[e.v].size();i++)//和e.v这个点相连的点全部扫描一遍 
			{
				
				int k=g[e.v][i].v;//和e.v这个点相连的点暂存于k 
				if(vis[k]==0)
				{
					int w=g[e.v][i].w;//k对应的权值 
					if(dis[k]>w)
					{
						dis[k]=w;
						q.push(Edges(k,w));
					}
				}
			}
		}
		
	}
	if(cnt<n)  return -1;
	return sum;
}
int main()
{
	while(cin>>n)
	{
		for(int i=0;i<n;i++)
		   g[i].clear();
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				int w;
				cin>>w;
				g[i].push_back(Edges(j,w));
			}
		}
		cout<<prim(g,n)<<endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值