zoukankan      html  css  js  c++  java
  • P4716-[模板]最小树形图

    正题

    题目链接:https://www.luogu.com.cn/problem/P4716


    题目大意

    给出(n)个点(m)条边的一张有向图,求以(r)为根的最小外向树。

    (1leq nleq 100,1leq mleq 10^4)


    解题思路

    考虑一种贪心,对于每个点我们先选出一个连入的最小的边权,但是这样可能产生环。

    考虑暴力将环去掉,我们枚举所有的环,然后将环缩成一个点,之后然后每个环外的边都减去入点所连接边的权值(可撤销贪心)。

    然后问题规模就缩小了,不断重复上述过程即可。

    时间复杂度(O(n(n+m)))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=110;
    struct node{
    	int x,y,w;
    }e[N*N];
    int n,m,r,h[N],pre[N],v[N],id[N],ans;
    int main()
    {
    	scanf("%d%d%d",&n,&m,&r);
    	for(int i=1;i<=m;i++)
    		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    	while(1){
    		memset(h,0x3f,sizeof(h));
    		memset(v,0,sizeof(v));
    		memset(id,0,sizeof(id));
    		for(int i=1;i<=m;i++)
    			if(e[i].x!=e[i].y&&e[i].w<h[e[i].y])
    				h[e[i].y]=e[i].w,pre[e[i].y]=e[i].x;
    		for(int i=1;i<=n;i++)
    			if(i!=r&&h[i]==h[0])return puts("-1")&0;
    		int cnt=0;
    		for(int p=1;p<=n;p++){
    			if(p==r)continue;
    			int x=p;ans+=h[x];
    			while(x!=r&&v[x]!=p&&!id[x])v[x]=p,x=pre[x];
    			if(x!=r&&!id[x]){
    				id[x]=++cnt;
    				for(int y=pre[x];y!=x;y=pre[y])id[y]=cnt;
    			}
    		}
    		if(cnt==0)break;
    		for(int i=1;i<=n;i++)
    			if(!id[i])id[i]=++cnt;
    		for(int i=1;i<=m;i++){
    			e[i].w-=h[e[i].y];
    			e[i].x=id[e[i].x];
    			e[i].y=id[e[i].y];
    		}
    		r=id[r];n=cnt;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    POJ 3258 (NOIP2015 D2T1跳石头)
    POJ 3122 二分
    POJ 3104 二分
    POJ 1995 快速幂
    409. Longest Palindrome
    389. Find the Difference
    381. Insert Delete GetRandom O(1)
    380. Insert Delete GetRandom O(1)
    355. Design Twitter
    347. Top K Frequent Elements (sort map)
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15164854.html
Copyright © 2011-2022 走看看