两种方式:
1.kruskal:归并边 存储方式:邻接表 时间复杂度:O(eloge) 适用于:稀疏网
2.Prim算法:归并点 存储方式:矩阵 时间复杂度:O(n^2) 适用于:稠密网
(1)Kruskal
SL:将边按照从小到大排序,通过判断父节点是否相同,不同可归并,归并边次数n-1
/*
Kruskal:最小生成树
原理:归并边;
*/
#include<iostream>
#include<algorithm>
using namespace std;
const int Max=10005;
struct Node
{
int u,v;
int w;
}e[Max];
int fa[Max];
int cnt=0;
bool cmp(Node a,Node b)
{
return a.w<b.w;
}
int init(int n)
{
for(int i=1;i<=n;++i)
fa[i]=i;
}
int getf(int x)
{
return fa[x]==x?fa[x]:getf(fa[x]);
}
int merge(int u,int v)
{
int tx=getf(u);
int ty=getf(v);
if(tx!=ty)
{
fa[ty]=tx;
return 1;
}
return 0;
}
int Kruskal(int n,int m)
{
int sum=0;
for(int i=1;i<=m;i++)
{
if(merge(e[i].u,e[i].v))
{
cnt++;
sum+=e[i].w;
}
if(cnt==n-1)
return sum;
}
}
int main()
{
int n,m;
cout<<"输入顶点个数及边数:"<<endl;
cin>>n>>m;
init(n);
cout<<"输入相关边信息:"<<endl;
for(int i=1;i<=m;++i)
{
cin>>e[i].u>>e[i].v>>e[i].w;
}
//对边排序
sort(e+1,e+1+m,cmp);
cout<<"按权值从小到大排序后:"<<endl;
cout<<"-------------------"<<endl;
for(int i=1;i<=m;i++)
{
cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].w<<" "<<endl;
}
cout<<"------------------"<<endl;
int sum=Kruskal(n,m);
cout<<"最小权值:"<<sum<<endl;
}
/*
input
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
output
19
*/
(2)Prim
/*
**最小生成树:
目的:获得最小权值
**注意条件:
1.避圈法
**方法:
1.Prim
2.Kruscal
*/
#include<iostream>
using namespace std;
const int Max=10005;
const int INF=99999999;
int mp[Max][Max];
int path[Max];
int dis[Max],vis[Max];
int cnt=0;
int Prim(int n)
{
cout<<"Starting"<<endl;
int sum=0;
for(int i=1;i<=n;i++)
{
dis[i]=mp[1][i];
}
int Min=INF,p;
vis[1]=1;
path[++cnt]=1;
for(int i=1;i<n;++i)
{
Min=INF;
for(int j=1;j<=n;j++)
{
if(Min>dis[j]&&!vis[j])
{
Min=dis[j];
p=j;
}
}
vis[p]=1;
sum+=dis[p];
path[++cnt]=p;
for(int k=1;k<=n;k++)
{
if(dis[k]>mp[p][k])
dis[k]=mp[p][k];
}
}
return sum;
}
int main()
{
int n,m,u,v,vl,c;
cout<<"---------1. 使用已给样例-------------"<<endl;
cout<<"---------2. 手动输入 -------------"<<endl;
cin>>c;
if(c==2)
{
cout<<"输入顶点个数和弧数:"<<endl;
cin>>n>>m;
}
else
{
n=3,m=3;
}
//初始化
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;j++)
mp[i][j]=INF;
}
if(c==2)
{
cout<<"相关联点的信息:"<<endl;
for(int i=0;i<m;++i)
{
cin>>u>>v>>vl;
if(mp[u][v]>vl)
mp[u][v]=mp[v][u]=vl;//当两顶点之间的值有多个时。取最小的
}
}
else
{
mp[1][2]=mp[2][1]=1;
mp[2][3]=mp[3][2]=1;
mp[1][3]=mp[3][1]=4;
}
int sum=Prim(n);
cout<<"矩阵显示"<<endl;
cout<<"------------------"<<endl;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;++j)
cout<<mp[i][j]<<" ";
cout<<endl;
}
cout<<"------------------"<<endl<<endl;
cout<<"路径是:"<<endl;
for(int i=1;i<=cnt;++i)
{
cout<<path[i];
if(i!=cnt)
cout<<"-->";
}
cout<<endl;
cout<<"最小权值:"<<endl;
cout<<sum<<endl;
// cout<<"1到各个顶点的最短路径:"<<endl;
// for(int i=2;i<=n;i++)
// {
// cout<<1<<"-->"<<i<<":"<<dis[i]<<endl;
// }
}
/*
input
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
output
19
*/