简要:
最小生成树算法
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;
}
结构体型