zoukankan      html  css  js  c++  java
  • hdu2121 最小树形图的虚根

    /*

    最小树形图的第二题,终于有了一些理解

    具体看注释

    */

    /*
    无定根的最小树形图
    建立虚root
    每次只找最短的那条入边
    最小树形图理解:
        第一步:寻找最短弧集E:扫一遍所有的边,找到每个点权值最小的入边,这一步会产生环
        第二步:对每个点 i 找环:通过第一步记录的前驱找环,如果找到了原点或退到了另一个环,点i找环失败 
        第三步:缩点,缩点就是染色,把每个环内的点染上同一种颜色,每个环内点打上同一个id
        第四步:更新一次边集:如果一条边连接两个不同颜色的点,就该边这条边的权值
    重复以上四步。
    
    最小树形图的root:root不需要入边 
    最小树形图的实质是最小生成树,所以用贪心的思想解决,但是贪心找入边时会生产环(第一步)
                                因此还得找另外一条边连到那个环中,才能解决这个环(第四步)
     
    不定根确定根需要加一个虚根,由虚根为超级源点建立最小生成树,
    这样由超级源点出发到达的第一个点就是实际最小生成树的根
    虚根和每条边链接一条虚边,其权值要大于实根的和,以此判断是否连了两条虚边(建图失败)
    
    如何找到那个实根:在不断形成环的过程中,会最先有一个点最先和虚根相连,这个点就是实根(实根是不需要入边的,但是在加了虚根后,实根不再是根) 
        贪心思想保证第一个和虚根链接的必定是实根 
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define ll long long 
    #define MAXN 1005
    #define INF 0x3f3f3f
    using namespace std;
    struct Edge{
        ll u,v,cost;
    }edge[MAXN*MAXN];
    ll pos; 
    int pre[MAXN],id[MAXN],visit[MAXN];
    ll in[MAXN];
    ll zhuliu(int root,int n,int m){
        int res=0;
        int u,v;
        while(1){
            for(int i=0;i<n;i++)
                in[i]=INF;
            for(int i=0;i<m;i++)
                if(edge[i].u!=edge[i].v && edge[i].cost<in[edge[i].v]){
                    in[edge[i].v]=edge[i].cost;
                    pre[edge[i].v]=edge[i].u;
                    if(edge[i].u==root)
                        pos=i;
                }
            for(int i=0;i<n;i++)
                if(i!=root && in[i]==INF)
                    return -1;
            
            int tn=0;
            memset(id,-1,sizeof id);
            memset(visit,-1,sizeof visit);
            in[root]=0;
            for(int i=0;i<n;i++){
                res+=in[i];
                v=i;
                while(visit[v]!=i && id[v]==-1 && v!=root){
                    visit[v]=i;
                    v=pre[v];
                }
                if(v!=root && id[v]==-1){
                    for(int u=pre[v];u!=v;u=pre[u])
                        id[u]=tn;
                    id[v]=tn++;
                }
            }
            
            if(tn==0)
                break;//已经没有环了 
            for(int i=0;i<n;i++)
                if(id[i]==-1)
                    id[i]=tn++;
                    
            for(int i=0;i<m;i++){//第四步,更新一次边集 
                int u=edge[i].u;
                int v=edge[i].v;
                edge[i].u=id[u];
                edge[i].v=id[v];
                if(id[u] != id[v])
                    edge[i].cost-=in[v]; 
            }
            n=tn;
            root=id[root];
        }
        return res;
    }
    int main(){
        ll n,m;
        while(scanf("%lld%lld",&n,&m)==2){
            ll sum=0;
            for(ll i=0;i<m;i++){
    
                scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].cost);
                edge[i].u++;edge[i].v++;
                sum+=edge[i].cost;
            }
            
            int root=n,tot=m;//加入虚根 
            for(ll i=m;i<n+m;i++){
                edge[i].u=0;
                edge[i].v=i-m+1;
                edge[i].cost=sum+1;
            }
                        
            ll ans=zhuliu(0,n+1,n+m);
            if(ans==-1 || ans-(sum+1)>=sum+1)
                printf("impossible
    
    ");
            else 
                printf("%lld %lld
    
    ",ans-(sum+1),pos-m);
        }
        return 0;
    } 
  • 相关阅读:
    EJB>依赖注入(dependency injection) 小强斋
    EJB>自定义安全域 小强斋
    EJB>定时服务(Timer Service) 小强斋
    EJB>依赖注入(dependency injection) 小强斋
    EJB>定时服务(Timer Service) 小强斋
    EJB>安全服务的具体开发 小强斋
    EJB>JMS(Java Message Service)和消息驱动bean 小强斋
    EJB>拦截器(Interceptor) 小强斋
    《做最好的员工》第二章:好员工擅长合作
    教你29招,让你在社交,职场上人人对你刮目相看 !
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9799684.html
Copyright © 2011-2022 走看看