码迷,mamicode.com
首页 > 其他好文 > 详细

最小树形图

时间:2020-01-22 23:40:33      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:缩点   情况   auto   mat   结束   最小   ++   line   tarjan   

每个点贪心找最小的前驱选上,然后分情况:
如果形成一棵树,那么算法结束;
否则对该图缩点,scc之间的边的权值赋值成 用这条边替代原来终点的前驱 的权值,表示换去一条环边,然后做最小树形图即可。
每轮至少缩去一个点,复杂度 \(O(n^2+nm)\)

void tarjan(int u)
{
    dfn[u]=low[u]=++ord;
    stk[++top]=u;
    ins[u]=1;
    int v=nxt[u];
    if(!dfn[v])
        tarjan(v),low[u]=min(low[u],low[v]);
    else if(ins[v])
        low[u]=min(low[u],dfn[v]);
    if(dfn[u]==low[u])
    {
        ++cnt;
        for(int x=stk[top];;x=stk[top])
        {
            --top;
            scc[x]=cnt;
            ins[x]=0;
            if(x==u)
                break;
        }
    }
}

int work(int n,vector<edge>e,int root)
{
    int ans=0;
    while(1)
    {
        vector<int>d(n+1,1e9);
        for(int i=1; i<=n; i++)
            nxt[i]=scc[i]=dfn[i]=low[i]=ins[i]=0;
        for(auto &k:e)
            if(k.u!=k.v&&k.w<d[k.v])
                d[k.v]=k.w,nxt[k.v]=k.u;
        nxt[root]=root;
        d[root]=0;
        for(int i=1; i<=n; i++)
        {
            if(!nxt[i])
                return -1;
            ans+=d[i];
        }
        top=ord=cnt=0;
        for(int i=1; i<=n; i++)
            if(!dfn[i])
                tarjan(i);
        if(cnt==n)
            break;
        vector<edge> ne;
        for(auto &k:e)
            if(scc[k.u]!=scc[k.v])
                ne.push_back((edge){scc[k.u],scc[k.v],k.w-d[k.v]});
        e=ne; n=cnt; root=scc[root];
    }
    return ans;
}

最小树形图

标签:缩点   情况   auto   mat   结束   最小   ++   line   tarjan   

原文地址:https://www.cnblogs.com/bestwyj/p/12229921.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!