教学地址:
算法核心:
(T集合包含生成树中的结点,V集合包含所有结点)
在连接T内顶点与V-T内顶点的边中选取权值最小的边(pu,u),将其作为MST(最小生成树)的边,并添加u至T中!
代码实现:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1000+10;
int n,ans,ecnt,m;
int head[maxn],vis[maxn];
int ma[maxn][maxn],d[maxn];
struct node
{
int u,v,next;
} E[maxn];
bool flag=false;
void add(int u,int v)
{
E[++ecnt].u=u;
E[ecnt].v=v;
E[ecnt].next=head[u];
head[u]=ecnt;
}
void prim()
{
memset(d,0x7f7f7f7f,sizeof(d));//注意初始化
int u;
d[1]=0;//以1为根节点
for(int i=1; i<=n; i++) //最多遍历n次
{
u=0;//注意是0,不是1
//找famous结点
for(int j=1; j<=n; j++)
{
if(!vis[j]&&d[j]<d[u]){
u=j;
}
}
vis[u]=1;
ans+=d[u];//最小生成树
//更新d,是全图更新,而非famous扩展出去的那几个点
for(int j=1; j<=n; j++)
{
if(!vis[j]&&ma[u][j]<d[j]&&ma[u][j]!=-1)
{
d[j]=ma[u][j];
}
}
}
}
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
cin>>ma[i][j];
}
}
prim();
cout<<ans;
return 0;
}
链式前向星实现
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=4e5+10;
int n,ans,ecnt,m;
int head[maxn],vis[maxn];
int d[maxn];
struct node
{
int u,v,w,next;
} E[maxn];
bool flag=false;
void add(int u,int v,int w)
{
E[++ecnt].u=u;
E[ecnt].v=v;
E[ecnt].w=w;
E[ecnt].next=head[u];
head[u]=ecnt;
}
void prim()
{
memset(d,0x7f7f7f7f,sizeof(d));//注意初始化
int u;
d[1]=0;//以1为根节点
for(int i=1; i<=n; i++) //最多遍历n次
{
u=0;//注意是0,不是1
//找famous结点
for(int j=1; j<=n; j++)
{
if(!vis[j]&&d[j]<d[u]){
u=j;
}
}
vis[u]=1;
ans+=d[u];//最小生成树
//更新d,是全图更新,而非famous扩展出去的那几个点
for(int i=head[u];i;i=E[i].next)
{
int v=E[i].v;
if(!vis[v]&&E[i].w<d[v])d[v]=E[i].w;
}
}
}
int main()
{
cin>>n>>m;
for(int i=1; i<=m; i++)
{
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
prim();
for(int i=1;i<=n;i++)
{
if(!vis[i]) {
cout<<"有孤立点"<<endl;
return 0;
}
}
cout<<ans;
return 0;
}
算法总结:
prim算法可以分为两个步骤
1、找到G-T集合中路径最小的点
2、更新数组d,注意是全图更新,而非只更新与白点相连的点
这两步相互依存,通过起点更新数组d,通过数组d,来找出新的起点!