最小生成树
定义无向连通图的最小生成树,为边权和最小的生成树。(生成树就是连接图里的某些边,使其成为一棵包含图中所有节点的树)。
类似于 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;
}
本文作者:cjrqwq
本文链接:https://www.cnblogs.com/yfzqwq/p/18492818
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现