最小生成树
定义无向连通图的最小生成树,为边权和最小的生成树。(生成树就是连接图里的某些边,使其成为一棵包含图中所有节点的树)。
类似于 dij,每次加入一个距离点集 最小的点。
- 把到所有点的距离 。
- 钦定一个点 ,将 。
- 找到最小的不属于 的 ,将
- 更新与 相连的边。
- 构成最小生成树,退出。
朴素版本的时间复杂度为:
#include<iostream>
#include<cstring>
using namespace std;
const int N=5e3+10,inf=0x3f3f3f3f;
int n,m;
int vis[N],f[N],dis[N],ans,a[N][N];
void prim() {
memset(dis,0x3f,sizeof dis);
dis[1]=0;
for(int i=1;i<=n;i++)
{
int mx=0;
for(int j=1;j<=n;j++)
if(dis[j]<dis[mx]&&!vis[j])
mx=j;
if(dis[mx]==inf)
{
ans=inf;
break;
}
ans+=dis[mx];vis[mx]=1;
for(int j=1;j<=n;j++)
if(!vis[j]&&dis[j]>a[mx][j])
dis[j]=a[mx][j];
}
if(ans!=inf)
cout<<ans;
else
cout<<"impossible";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
memset(a,0x3f,sizeof a);
cin>>n>>m;
for(int i=1,x,y,z;i<=m;i++)
cin>>x>>y>>z,a[x][y]=a[y][x]=min(z,a[x][y]);
prim();
return 0;
}
在稀疏图中, 与 相近,使用优先队列进行优化,可以将复杂度变为 。但此时需要注意:
- 在稠密图中,请使用朴素版本。
- 在稀疏图中,请使用堆优化版。
#include<iostream>
#include<cstring>
#include<queue>
#define pii pair<int,int>
using namespace std;
const int N=5e2+10,M=1e5+10;
int n,m;
int dis[N],vis[N],ans,cnt;
priority_queue<pii,vector<pii>,greater<pii>>q;
struct Node
{
int to,next,dis;
}edge[M<<1];
int ne,head[N];
void ae(int from,int to,int dis)
{
edge[++ne].to=to;
edge[ne].next=head[from];
edge[ne].dis=dis;
head[from]=ne;
}
void prim() {
memset(dis,0x3f,sizeof dis);
dis[1]=0;
q.push({0,1});
while(!q.empty()&&cnt<n)
{
int min_dis=q.top().first,from=q.top().second;
q.pop();
if(vis[from])
continue;
vis[from]=1;
ans+=min_dis;
cnt++;
for(int i=head[from];i;i=edge[i].next)
{
int to=edge[i].to,tmp_dis=edge[i].dis;
if(dis[to]>tmp_dis)
{
dis[to]=tmp_dis;
q.push({dis[to],to});
}
}
}
if(cnt==n)
cout<<ans;
else
cout<<"impossible";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1,x,y,z;i<=m;i++)
{
cin>>x>>y>>z;
ae(x,y,z),ae(y,x,z);
}
prim();
return 0;
}
码量比较大,不是很友好。
文中模板均只输出了最小生成树的权值和,还可以实现输出边等操作。
将边权升序排列,当加入该边无环时,加入边,直到有 条边。
- 将边按边权升序排列。
- 使用并查集维护所有点。遍历所有边,设当前边由 到 。若 ,即构成环,不加入。
- 加入了 条边,退出。
#include<iostream>
#include<algorithm>
using namespace std;
#define x(_) x[mp[_]]
#define y(_) y[mp[_]]
#define z(_) z[mp[_]]
const int N=1e5+10,M=2e5+10;
int n,m;
int x[M],y[M],z[M],mp[M];
int fa[N];
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
int ans,cnt;
void kruskal()
{
for(int i=1;i<=n;i++)
fa[i]=i;
sort(mp+1,mp+m+1,[](int a,int b){return z[a]<z[b];});
for(int i=1;i<=m;i++)
{
int fx=find(x(i)),fy=find(y(i));
if(fx==fy) continue;
ans+=z(i),cnt++;
fa[fx]=fa[fy];
}
if(cnt<n-1)
cout<<"orz";
else
cout<<ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;mp[i]=i,i++)
cin>>x[i]>>y[i]>>z[i];
kruskal();
return 0;
}

浙公网安备 33010602011771号