当前位置: 首页 > news >正文

[图论]Prim

Prim

  • 本质:BFS+贪心,对点进行操作。与最短路Dijkstra算法是“孪生兄弟”。
  • 存储结构:链式前向星
  • 适用对象:可为负权图,可求最大生成树
  • 核心思想:最近的邻接点一定在最小生成树(MST)上,对点的最近邻接点贪心。
  • 算法流程:设源点 s s s(任意点),MST已选点集 { S } \set{S} {S}(初始 { S } = ∅ \set{S}=\varnothing {S}=);各点当前到已选点集 { S } \set{S} {S}的最小边权 { d i s } \set{dis} {dis}(初始 { d i s } \set{dis} {dis}:非 s : + ∞ s:+\infty s:+,表示该点目前不可达; s = 0 s=0 s=0);当前MST方案数组 t r e e tree tree(存储其上个源点,初始化为 − 1 -1 1表示无方案),待算法结束后极为最终方案;当前轮起点 U U U U U U邻接点集 { V } \set{V} {V},邻接点权值集 { W } \set{W} {W}
    循环执行下列步骤,直到点集 { S } \set{S} {S}包含所有顶点,或剩余点无法进入 { S } \set{S} {S}
    1. 考查最近顶点(贪心):从全体点集中,找出先前不在 { S } \set{S} {S}中(未被考查)且距点集 { S } \set{S} {S}最近( d i s dis dis最小)的顶点,作为当前轮起点 U U U(首次即为源点 s s s),将其进入 { S } \set{S} {S}(考查顶点 U U U)
    2. 扩散邻接点(BFS扩散):扩散 U U U的邻接点且先前未被考查的顶点 V V V,检查是否能通过 U U U而使其距点集 { S } \set{S} {S}更短( d i s dis dis更小)。若更短,则更新该点 d i s dis dis,并更新路径: d i s [ V ] = m i n ( d i s [ V ] , W ) dis[V]=min(dis[V],W) dis[V]=min(dis[V],W), t r e e [ V ] = U tree[V]=U tree[V]=U
  • Prim算法与最短路算法Dijkstra是“孪生兄弟”。与Dijkstra不同之处在于更新操作中,Prim为更新为所有点到 { S } \set{S} {S}整体的距离(即 d i s [ V ] = m i n ( d i s [ V ] , W ) dis[V]=min(dis[V],W) dis[V]=min(dis[V],W));而Dijkstra为更新所有点到 { S } \set{S} {S}特定一点(源点 s s s)的距离(即 d i s [ V ] = m i n ( d i s [ V ] , d i s [ U ] + W ) dis[V]=min(dis[V],dis[U]+W) dis[V]=min(dis[V],dis[U]+W))。
  • 复杂度:朴素版 O ( V 2 ) O(V^2) O(V2),二叉堆优化版 O ( V log ⁡ 2 E ) O(V\log_2E) O(Vlog2E)
using ll=long long;
using pll=pair<ll,ll>;
const ll INF=__LONG_LONG_MAX__;
ll n,m,s;//点数,边数,源点
struct vertex{int e=-1;
}v[n];
struct edge{int u,v,w,n=-1;
}e[m];

注:若无特殊说明,本文默认顶点均为从0起编号。

朴素版

  • 选目前 d i s dis dis最小点 U U U的3个条件:该点未被考查,该点 d i s dis dis非无穷,该点 d i s dis dis更小
  • 扩散至 U U U邻接点 V V V的3个条件:该邻接点未被考查,边权值 W W W非无穷, V V V通过 U U U而使 d i s dis dis更短
int prim() {vector<bool>S(n,0);vector<ll>dis(n,INF),tree(n,-1);ll s=0,ans=0;dis[s]=0;for (int j=0;j<n;j++){ll U=-1,minn=INF;for(ll i=0;i<n;i++)if(!S[i]&&dis[i]!=INF&&dis[i]<minn) U=i,minn=dis[i];if(U==-1) return -1;//剩余点均不可达,不存在MSTS[U]=1;ans+=dis[U];for (ll i=v[U].e;~i;i=e[i].n){//~i:i!=-1ll V=e[i].v,W=e[i].w;if (!S[V]&&W!=INF&&dis[V]>W)//与Dijkstra唯一不同点dis[V]=min(dis[V],W),tree[V]=U;}}return ans;
}

若求最大生成树: d i s dis dis应初始化为 − ∞ -\infty ;找 d i s dis dis最大顶点;更新条件改为 d i s [ V ] < W dis[V]<W dis[V]<W

二叉堆优化版

优化点:另设顶点的小根堆 Q Q Q,其结构为 { d i s , i n d e x } \set{dis,index} {dis,index},可动态维护当前 d i s dis dis最小点 U U U

另设计数器 c n t cnt cnt,若 c n t < V cnt<V cnt<V,则证明是非连通图,无法构成MST。

  • 选目前 d i s dis dis最小点 U U U的3个条件:该点未被考查,该点 d i s dis dis非无穷,该点 d i s dis dis更小。

  • 扩散至 U U U邻接点 V V V的3个条件:该邻接点未被考查,边权值 W W W非无穷, V V V通过 U U U而使 d i s dis dis更短

int prim() {vector<ll>dis(n,INF),tree(n,-1);vector<bool>S(n,0);priority_queue<pll,vector<pll>,greater<>>pq;int ans=0,cnt=0,s=0;dis[s]=0,pq.push({dis[s],s});//dis,indexwhile(pq.size()){ll U=pq.top().second;pq.pop();if(S[U]) continue;S[U]=1,ans+=dis[U],cnt++;for(ll i=v[U].e;~i;i=e[i].n){//~i:i!=-1ll V=e[i].v,W=e[i].w;if(!S[V]&&W!=INF&&dis[V]>W){//与Dijkstra唯一不同点dis[V]=W,tree[V]=U;pq.push({dis[V],V});}}}if(cnt<n) return -1;return ans;
}

若求最大生成树: d i s dis dis应初始化为 − ∞ -\infty ;维护大根堆;更新条件改为 d i s [ V ] < W dis[V]<W dis[V]<W

相关文章:

  • XCZU4CG‑2SFVC784I 赛灵思 FPGA XilinxZynq UltraScale+ MPSoC
  • 新型多机器人协作运输系统,轻松应对复杂路面
  • 算法思想之分治-归并
  • 【Linux】第八章 监控和管理Linux进程
  • SpringBoot——配置文件
  • 【机器人创新创业应需明确产品定位与方向指南】
  • EMIF详解
  • RPCRT4!OSF_CCONNECTION::OSF_CCONNECTION函数分析之初始化中的u.ConnSendContext----RPC源代码分析
  • 如何简单几步使用 FFmpeg 将任何音频转为 MP3?
  • 插件架构实践
  • 0.深入探秘 Rust Web 框架 Axum
  • 基于 Django 进行 Python 开发
  • Telecom 源码分析计划
  • JUC学习(1) 线程和进程
  • SQL Server 游标介绍
  • 《MySQL:MySQL表结构的基本操作》
  • webgl入门实例-07顶点缓冲区示例
  • 什么是分库分表?
  • 制作Unoconv项目的Docker镜像
  • 部署若依前后端分离
  • 首次采用“顶置主星+侧挂从星”布局,长二丁“1箭12星”发射成功
  • 国务院办公厅印发《国务院2025年度立法工作计划》
  • 郑培凯:汤显祖的“至情”与罗汝芳的“赤子之心”
  • 特朗普访中东绕行以色列,专家:凸显美以利益分歧扩大
  • 极限拉扯上任巴西,安切洛蒂开启夏窗主帅大挪移?
  • 福建宁德市长张永宁拟任设区市党委正职,曾获评全国优秀县委书记