最小树形图

这篇博客介绍了最小树形图的概念,特别是在有向图中的应用。文章详细阐述了朱刘算法,一种用于求解最小树形图的O(nm)时间复杂度算法,包括算法流程和如何处理环的问题。此外,还给出了两个典型例题,分别是定根和不定根最小树形图的解题思路和代码实现。
摘要由CSDN通过智能技术生成

最小树形图

1.算法分析

有向图上的最小生成树(Directed Minimum Spanning Tree)称为最小树形图。常用的算法是朱刘算法(也称 Edmonds 算法),可以在 O ( n m ) O(nm) O(nm) 时间内解决最小树形图问题。

该算法最后能够找到一个从根出发,能够走到任意一个点的一个最小权值有向的树。

流程

  1. 对于每个点,选择它入度最小的那条边
  2. 如果没有环,算法终止;否则进行缩环并更新其他点到环的距离。
  3. 缩点时:对于环内部的边,删去;对于终点在环内的,边权变为w外-w环内。

2.模板

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 100 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
typedef pair<int, int> PII;
int id[N], vis[N], pre[N], pos;  // id记录每个点属于哪个环,vis用来判断几个点是否处于一个环内,
                                 // pre记录每个点的前一个节点,pos记录虚节点
double dis[N], INF = 1e17;  // dis记录每个点到最小生成树的距离
PII point[N];
// 定义边的结构
struct node {
   
    int u, v;
    double cost;
} edge[N * N];
int n, m;
// 朱刘算法
// root:根节点(记得下标从0开始)
// V点数0~V-1
// E边数0~E-1
double zhuliu(int root, int V, int E) {
   
    double sum = 0;  // 计算当前最小树形图的边权值和
    while (true) {
   
        // 把每个点到最小生成树的距离置为无穷
        for (int i = 0; i < V; i++) {
   
            dis[i] = INF;
        }

        //找最小入边
        for (int i = 0; i < E; i++) {
   
            int u = edge[i].u, v = edge[i].v;
            if (u != v && dis[v] > edge[i].cost) {
   
                dis[v] = edge[i].cost;
                pre[v] = u;
                if (u == root) {
   
                    pos = i;
                }
            }
        }

        //某点不存在入边,算法结束
        for (int i = 0; i < V; i++) {
   
            if (dis[i] == INF && i != root) return -1;
        }
        int cnt = 0;  // 记录当前这张图内点的个数
        memset(id, -1, sizeof id);
        memset(vis, -1, sizeof vis);
        dis[root] = 0;  // 把根节点放入最小树形图

        //找环
        for (int i = 0; i < V; i++) {
   
            int v = i;
            sum += dis[i];
            while (id[v] == -1 && vis[v] != i && v != root) {
   
                vis[v] = i;
                v = pre[v];
            }

            //找到环的时候缩点编号
            if (id[v] == -1 && v != root) {
   
                for (int u = pre[v]; u != v; u = pre[u]) {
   
                    id[u] = cnt;  // 把u点放入编号为cnt的环内
                }
                id[v] = cnt++;
            }
        }

        //如果没有环,则以找到最小树形图,算法结束
        if (!cnt) break;

        //把余下的不在环里的点编号
        for (int i = 0; i < V; i++) {
   
            if (id[i] == -1) id[i] = cnt++;
        }

        //更新距离
        for (int i = 0; i < E; i++
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值