• 【洛谷P4716】【模板】最小树形图


    题目

    题目链接:https://www.luogu.com.cn/problem/P4716
    给定包含 (n) 个结点, (m) 条有向边的一个图。试求一棵以结点 (r) 为根的最小树形图,并输出最小树形图每条边的权值之和,如果没有以 (r) 为根的最小树形图,输出 (-1)
    (nleq 100)(mleq 10^4)

    思路

    这道题求的是外向树,下文根据习惯,写的是内向树。只需要把所有边反过来就可以了。
    首先如果这张图是一个 DAG,那么求出除了根节点外所有点的最小出边,这些出边形成的就一定是最小树形图。因为一定恰好选择 (n-1) 条边,且一定没有环。
    所以如果除了根以外,存在一个点没有出边,那么就没有最小树形图。
    对于一张普通的有向图,如果我们跑上述做法,得到的可能是若干环和一个内向树。对于一个点 (x),它最小的出边连向的是 (y),且 (x) 在一个环上。如果我们需要把出边改成到达 (z),那么它的代价是 (dis(x,z)-dis(x,y))
    于是可以把所有的环缩成一个点,并把选择的边的权值都加上,然后对于一条没有选择的边 ((x,z)),如果 (x) 的出边是到 (y),把这条边的权值改为 (dis(x,z)-dis(x,y)) 即可。
    因为如果有环,就会把环缩成一个点,每次的点数至少减 (1),然后可以转化为一个更小规模的相同问题。当不存在环的时候就找出了最小树形图。
    时间复杂度 (O(nm))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=10010,Inf=1e9;
    int n,m,rt,tot,mind[N],fa[N],top[N],bel[N];
    
    struct edge
    {
    	int u,v,dis;
    }e[N];
    
    int zhuliu()
    {
    	int ans=0;
    	while (1)
    	{
    		for (int i=1;i<=n;i++)
    			mind[i]=Inf,fa[i]=top[i]=bel[i]=0;
    		mind[rt]=tot=0;
    		for (int i=1;i<=m;i++)
    		{
    			int u=e[i].u,v=e[i].v,d=e[i].dis;
    			if (u!=v && mind[v]>d) fa[v]=top[v]=u,mind[v]=d;
    		}
    		for (int i=1,j;i<=n;i++)
    		{
    			if (mind[i]==Inf) return -1;
    			ans+=mind[i]; j=i;
    			while (j!=rt && !bel[j] && top[j]!=i)
    				top[j]=i,j=fa[j];
    			if (j!=rt && !bel[j])
    			{
    				bel[j]=++tot;
    				for (int k=fa[j];k!=j;k=fa[k]) bel[k]=tot;
    			}
    		}
    		if (!tot) return ans;
    		for (int i=1;i<=n;i++)
    			if (!bel[i]) bel[i]=++tot;
    		for (int i=1;i<=m;i++)
    			e[i]=(edge){bel[e[i].u],bel[e[i].v],e[i].dis-mind[e[i].v]};
    		n=tot; rt=bel[rt];
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&rt);
    	for (int i=1;i<=m;i++)
    		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].dis);
    	cout<<zhuliu();
    	return 0;
    }
    
  • 相关阅读:
    web网页测试用例(非常实用)
    怎么做web接口测试
    我的周记13——”离开,是为了更好的回来"
    Lambda 表达式常用函数
    IEnumberable<T>接口
    Linq的学习
    未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。
    拉姆达表达式的笔记
    注册今日头条
    爬取百思不得姐的段子
  • 原文地址:https://www.cnblogs.com/stoorz/p/15158615.html
Copyright © 2020-2023  润新知