prim(邻接矩阵存图):
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N=1e3+5;
int graph[N][N];
int n,m;
void prim(int graph[][N],int n){
int dis[N];//dis[i]:MST到i点的最小距离 dis[i]=0表示已经加入最小生成树
int mst[N];//mst[j]:表示j点与MST相连接的点,mst[j]=0表示已经加入最小生成树
int sum=0;//记录最小生成树权值和
mst[1]=0;//先把1加入最小生成树
for(int i=2;i<=n;i++){//2到n的每个点与MST的距离就是 graph[1][i]
dis[i]=graph[1][i];
mst[i]=1;
}
for(int i=2;i<=n;i++){//n个点生成的MST循环n-1次
int min=INF;
int minid=0;
for(int j=2;j<=n;j++){//遍历剩余的点到MST的距离,找最小的加入MST
if(dis[j]<min&&dis[j]){
min=dis[j];
minid=j;
}
}
printf("V%d--V%d:%d\n",mst[minid],minid,min);
sum+=min;
dis[minid]=0;//将minid加入MST
for(int j=2;j<=n;j++){//更新剩余点到MST的最小距离
if(graph[j][minid]<dis[j]){
dis[j]=graph[j][minid];
mst[j]=minid;
}
}
}
cout<<"最小权值:"<<sum<<endl;
}
int main(){
cin>>n>>m;
int u,v,w;
for(int i=1;i<=n;i++){//初始化图
for(int j=1;j<=n;j++){
if(i!=j) graph[i][j]=INF;
else graph[i][j]=0;
}
}
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
graph[u][v]=w;
graph[v][u]=w;
}
prim(graph,n);
return 0;
}
/*
6 10
1 2 2
1 6 1
1 5 4
2 6 3
2 3 1
3 6 5
3 4 3
4 6 4
4 5 2
5 6 3
ans=9
*/
给的样例图:
prim(链式前向星存图):
链式前向星b站视频
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 5005
#define maxm 200005
struct edge
{
int to,w,next;
}e[maxm*2];
int head[maxn],dis[maxn],cnt,n,m,tot,now=1,ans;
//dis[i]:MST到i点的最小距离 ,比如说1和2号节点已经加入了MST,那么dis[3]就等于min(1->3,2->3)
bool vis[maxn];//
void add(int u,int v,int w)//链式前向星加边
{
e[++cnt].to=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
int prim()
{
//先把dis数组附为极大值
for( int i=2;i<=n;++i) dis[i]=inf;
for( int i=head[1];i;i=e[i].next)//遍历与1直接相连的点,
{
dis[e[i].to]=min(dis[e[i].to] ,e[i].w);
}
for(int k=2;k<=n;k++)//n个点生成的MST循环n-1次,最小生成树边数=点数-1
{
int minn=inf;//把minn置为极大值
vis[now]=1;//标记点已经走过
//枚举每一个没有使用的点
//找出最小值作为新边
//注意这里不是枚举now点的所有连边,而是1~n
for( int i=1;i<=n;++i)
{
if(!vis[i]&&minn>dis[i])
{
minn=dis[i];
now=i;
}
}
ans+=minn;
//枚举now的所有连边,更新dis数组
//模拟第一遍now=6
for( int i=head[now];i;i=e[i].next)
{
int v=e[i].to; //now=6时 v=2,3,4,5
if(dis[v]>e[i].w&&!vis[v])//e[i].w是now到v的边的权值
{
dis[v]=e[i].w;
}
}
}
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1,u,v,w;i<=m;++i)//无向边
{
cin>>u>>v>>w;
add(u,v,w),add(v,u,w);
}
printf("%d",prim());
return 0;
}
/*
*/
Kruskal(并查集):
#include<bits/stdc++.h>
using namespace std;
struct Edge
{
int u,v,w;
// bool operator <(const Edge& Temp)const{
// return w<Temp.w;
// }
}edge[200005];
int fa[5005],n,m,ans,ufa,vfa,cnt;
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
int find(int x)//找根节点
{
if(fa[x]!=x)fa[x] = find(fa[x]);
return fa[x];
}
void kruskal()
{
sort(edge,edge+m,cmp); //边排序
for( int i=0;i<m;i++)//m条边
{
ufa=find(edge[i].u);
vfa=find(edge[i].v);
if(ufa==vfa) continue;//两个点已联通,该边不需要加入MST
ans+=edge[i].w; //将此边权计入答案
fa[vfa]=ufa; //将ufa、vfa合并
cnt++;//循环结束条件,及边数为点数减一时
if(cnt==n-1) break;
}
}
int main()
{
cin>>n>>m;//n点 m条边
for( int i=1;i<=n;i++)fa[i]=i;//初始化fa数组
for( int i=0;i<m;i++)
{
cin>>edge[i].u>>edge[i].v>>edge[i].w;
}
kruskal();
printf("%d",ans);
return 0;
}