HDU 2121 Ice_cream’s world II 最小树形图

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2121

题意:求一个有向图的不定根的最小树形图

构造一个虚根,将所有点都连向虚根,权值为所有边总和+1

然后用朱刘算法跑一遍

因为枚举的顺序是从小到大,所以得出的根一定是最小的字典序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
const int N=2e4+5;
struct p
{
    int u,v,w;
};
p a[N];
int in[N],pre[N],id[N],use[N];
int pos;
int solve(int root,int V,int E)
{
    int ans=0;
    while(1)
    {
        memset(in,0x3f,sizeof(in));
        for(int i=0;i<E;i++)
        {
            int u=a[i].u,v=a[i].v;
            if (a[i].w<in[v]&&u!=v)
            {
                pre[v]=u;
                in[v]=a[i].w;
                if (u==root)
                    pos=i;
            }
        }
        for(int i=0;i<V;i++)
        {
            if (i==root) continue;
            if (in[i]==0x3f3f3f3f) return -1;
        }
        int tot=0;
        memset(id,-1,sizeof(id));
        memset(use,-1,sizeof(use));
        in[root]=0;
        for(int i=0;i<V;i++)
        {
            ans+=in[i];
            int v=i;
            while(use[v]!=i&&id[v]==-1&&v!=root)
            {
                use[v]=i;
                v=pre[v];
            }
            if (v!=root&&id[v]==-1)
            {
                for(int u=pre[v];u!=v;u=pre[u])
                    id[u]=tot;
                id[v]=tot++;
            }
        }
        if (tot==0) break;
        for(int i=0;i<V;i++)
            if (id[i]==-1) id[i]=tot++;
        for(int i=0;i<E;i++)
        {
            int u=a[i].u,v=a[i].v;
            a[i].u=id[u];
            a[i].v=id[v];
            if (id[u]!=id[v])
                a[i].w-=in[v];
        }
        V=tot;
        root=id[root];
    }
    return ans;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int sum=1;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
            a[i].u++;a[i].v++;
            sum+=a[i].w;
        }
        for(int i=m;i<m+n;i++)
        {
            a[i].u=0;a[i].v=i-m+1;
            a[i].w=sum;
        }
        int ans=solve(0,n+1,n+m);
        if (ans==-1||ans-sum>=sum)
            printf("impossible
");
        else printf("%d %d
",ans-sum,pos-m);
        printf("
");
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/bk-201/p/9318342.html