图论之最小生成树

简要:

最小生成树算法
1、prim(稠密图,邻接矩阵)
O(n^2) 
s和V-s集合,每次找两栖边最短的在V-s集合里的加入到s里面去
直到边为n-1条*/

2、Kruskal(稀疏图,邻接表)O(eloge),与点数无关 
s集合里包含所有顶点,且每个顶点自成一个连通分量
将边排序,依次将最短的边且不够成回路的加入到s集合里去 ,直到加入了n--1条边 
 

最小生成树:即最小权重生成树的简称

一个有n个结点的连通图的生成树是原图的一个极小的连通子图,且包含原图中的所有n个结点,

并且有保持图连同的最少的边

朴素Prim(V,E,W)V=(1,2,..N)

贪心策略

算法思路:

1.将第一个结点放入s集合//可以直接循环里

2、while(V-S!=NULL){//还有结点没有进到s集合的情况下(执行O(n))

从 V-S中选择j号结点(j满足它到S中某个结点的权值是所有连接V-S与S那些边里面最小的)

将j挑到S集合里O(n)

}

算法步骤

1.初始化d[i]->0x3f3f3f3f

2.执行n次(即V-S)

{

3.找到离s集合最近的点t,

4.用t更新其他点到集合的距离
}

/*给定n个点m条边的无向图,图中可能存在重边和自环
边权可能为负数,求最小生成树的树边权重之和,如果
不存在则输出impossible
*/

/*4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4


6
*/

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=510;//稠密图 
int g[N][N];//第一维表示起点,第二维表示终点,其值表示边权
bool s[N];//最小生成树的集合
const int INF=0x3f3f3f3f;
int d[N] ;//记录从一个点到另一个点的最小
int n,m;//n个点m条边 
 int Prim()
 {
 	memset(d,0x3f,sizeof d);//将距离初始化为正无穷
 	int res=0;//记录最小生成树的权重之和 
	 for(int i=0;i<n;i++){//遍历n次 
	 	int t=-1;// 用来找到里s集合最近的结点编号
		 for(int j=1;j<=n;j++)//编号从1开始 
		 	if(!s[j]&&(t==-1||d[t]>d[j]))//如果j这个点不在最小生成树集合里并且(还没有找到一个最近的结点或者有一个更近的结点)
			  t=j;
		  if(i&&d[t]==INF) return INF;//如果不是第一个点或者没有找到t,即说明图不连通 
		  if(i) res+=d[t];
		 for(int j=1;j<=n;j++)d[j]=min(d[j],g[t][j]);//这个点到集合的距离 
		  s[t]=true;
		  
	 } 
	 return res; 
 	
 }
int main()
{
	cin>>n>>m;
	memset(g,0x3f,sizeof g);
	for(int i=0;i<m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		g[x][y]=g[y][x]=min(g[x][y],z);//无向边处理,重边则保留权重最小的边权 
	}
	int t=Prim();
	if(t==INF) puts("impossible");
	else printf("%d",t);
	return 0; 
 } 

结构体型

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值