传送门
最小生成树问题:带权无向图求最小连通代价
①裸的prim:
最朴素的prim:邻接矩阵、搜索:O(n^2)
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e3+10,inf=0x3f3f3f3f;
int g[N][N],dist[N],res,m,n;
bool st[N] ;
int prim()
{
int res=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[t]>dist[j]))
t=j;
st[t]=true;
if(i&&dist[t]==inf)return inf;
if(i)res+=dist[t];
for(int j=1;j<=n;j++)
dist[j]=min(dist[j],g[j][t]);
}
return res;
}
int main()
{
cin>>n>>m;
memset(g,0x3f,sizeof g);
memset(dist,0x3f,sizeof dist);
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=min(g[a][b],c);
}
int t=prim();
if(t==inf)puts("-1");
else cout<<t;
}
②裸kruskal: O(mlogn)
并查集思想:
Ⅰ先将各边按权重按从小到大排序 O(mlogn)
Ⅱ枚举每条边的a,b和权重,如果ab不连通,将这条边加入集合中
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e3+10,inf=0x3f3f3f3f;
struct Edge
{
int a,b,w;
bool operator < (const Edge&W)const
{
return w<W.w;
}
}edge[N*3];
int n,m,p[N];
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int kruskal()
{
sort(edge,edge+m);
for(int i=1;i<=n;i++)p[i]=i;
int res=0,cnt=0;
for(int i=0;i<m;i++)
{
int a=edge[i].a,b=edge[i].b,w=edge[i].w;
a=find(a),b=find(b);
if(a!=b)
{
p[a]=b;
res+=w;
cnt++;
}
}
if(cnt<n-1)return inf;
return res;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
edge[i]={
a,b,c};
}
int t=kruskal();
if(t==inf)puts("-1");
else cout<<t;
}