洛谷4716 【模板】最小树形图

本文深入讲解了朱刘算法,一种用于寻找以特定节点为根的最小外向生成树的高效算法。通过逐步介绍算法流程,包括贪心选择、环检测与压缩等关键步骤,以及附带的代码实现,帮助读者理解其原理与应用。该算法适用于图论问题,特别在处理网络优化、最短路径等领域有广泛用途。

类似于最小生成树一样的东西

就是以给定的rt为根的最小外向生成树【内向直接建反边也行

然后算法是朱刘算法 大体过程就是先贪心选每个点的最小入边 然后暴力找环

没有环的话就是算法结束 返回即可 不然就是把这个环缩成一个点然后他的入边都要-=mn[v]就是拥有相同终点的边需要减掉变成增加量一样

如果要输出方案的话就需要还原 还原的话记录一下哪些边用过然后拆环即可

这个玩意时间复杂度貌似是O(nm)

但是我请教了一下巨佬们 大概这个是最劣复杂度 一般是不会达到的

可以理解为O(能过)就行了

代码如下。

//Love and Freedom.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define ll long long
#define N 110
#define M 10010
using namespace std;

struct edge{int u,v,c;}e[M];
int pre[N],mn[N],id[N],vis[N];
int n,m;
int zlal(int rt)
{
    int res = 0;
    while(1)
    {
        for(int i=1;i<=n;i++)    mn[i] = inf;
        for(int i=1;i<=m;i++)
            if(e[i].u != e[i].v && mn[e[i].v]>e[i].c)
            {
                mn[e[i].v] = e[i].c; pre[e[i].v] = e[i].u;
            }
        for(int i=1;i<=n;i++)    if(i!=rt && mn[i]==inf)    return -1;
        int tn = 0,u,v;
        memset(id,0,sizeof(id)); memset(vis,0,sizeof(vis));
        mn[rt] = 0;
        for(int i=1;i<=n;i++)
        {
            res += mn[i]; v=i;
            while(v!=rt && !id[v] && vis[v]!=i)
                vis[v] = i, v = pre[v];
            if(v!=rt && !id[v])
            {
                ++tn;
                for(u=pre[v];u!=v;u=pre[u])
                    id[u] = tn;
                id[v] = tn;
            }
        }
        if(!tn)    break;
        for(int i=1;i<=n;i++)    if(!id[i])
            id[i] = ++tn;
        for(int i=1;i<=m;i++)
        {
            v = e[i].v;
            e[i].u = id[e[i].u];
            e[i].v = id[e[i].v];
            if(e[i].u != e[i].v)
                e[i].c -= mn[v];
        }
        n = tn; rt = id[rt];
    }
    return res;
}
int main()
{
    int r;    scanf("%d%d%d",&n,&m,&r);
    for(int i=1;i<=m;i++)    scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);
    printf("%d\n",zlal(r));
    return 0;
}
/**
3 2 1
1 3 0
3 2 1
*/
View Code

 

转载于:https://www.cnblogs.com/hanyuweining/p/10366713.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值