朱刘算法
有向图的类Prim算法,找有向图的最小生成树
最小树形图
树形图:
- 无有向环
- 除了根节点外,每个点入度为1
以某个点为根的一棵有向树,其边权之和为图中所有树形图中是最小的称为最小树形图。
朱刘算法 O(nm)O(nm)O(nm)
(1) 除了根节点外对每个点选取一条边权最小的入边
(2)判断当前(选出的边)组成的图中有无环
1.若无环:则说明当前图已经为构造好的最小生成树,算法结束
2.若有环:进行第(3)步
(3)将构造的图进行强连通分量缩点,得到新图G′G'G′,对于G′G'G′中的所有边
1.如果是环中的边:直接删去
2.如果终点在环内(即新缩的点):更新此边权权值为W−W环内W-W_{环内}W−W环内
3.其他边:不变
然后继续从(1)开始迭代
当迭代完成后,所有选择的边的边权之和就是最终的答案。
邻接矩阵版本:
由于复杂度是
O(nm)
,因此在存储图的时候不需要背邻接表的板子,直接背邻接矩阵的即可。
板子:
const int N = 110,M=2e4+10,INF=1e8;
int n,m,r;
int d[N][N],bd[N][N],g[N][N];
int pre[N],bpre[N];
int dfn[N],low[N],timestamp,stk[N],top;
int id[N],scc_cnt;
bool st[N],ins[N];
void dfs(int u){
st[u]=true;
for(int i=1;i<=n;++i)
if(d[u][i]<INF&&!st[i])
dfs(i);
}
bool check_con(){
memset(st,0,sizeof st);
dfs(r);
rep(i,1,n)
if(!st[i])
return false;
return true;
}
void tarjan(int u){
dfn[u]=low[u]=++timestamp;
stk[++top]=u;ins[u]=true;
int j=pre[u];
if(!dfn[j]){
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(ins[j]) low[u]=min(low[u],dfn