HDU 3072 Intelligence System 传递的最小费用

题意:人和人之间传递消息,然后一些人到人的传递需要代价,如果一个人可以和另一个人直接或者间接的相互传递,那么他们之间的传递代价忽略不计,问说有人都知道消息的最小代价?


想法:显然tarjan缩点,然后用最小树形图求解,或者小贪心一下,因为最小树形图只跑了一层,显然每一个团体都是从另一个团体得到消息,又因为只有一个入度为0缩点(Believe kzc_tc’s working! There always is a way for him to communicate with all other intelligence personnel.),那么只要得到可以传送到这个团体的所有代价中取出最小的即可。


#include<iostream>
#include<cstring>
#include<stack>
#include<cstdio>
#define INF 0x7ffffff
#define mm(x) memset(x,0,sizeof(x))
using namespace std;
const int N=50000+9;
const int M=100000+9;
stack<int>s;
struct node
{
    int to,next;
    int w;
}G[M];
struct edge
{
    int u,v,w;
}NG[M];
int indegree[N];
int instack[N],paint[N],col,index,dfn[N],low[N];
int head[N],cnt,Ncnt;
class tarjan
{
    public:
        int MIN(int a,int b)
        {
            if(a<b) return a;
            return b;
        }
        void Init()
        {
            while(!s.empty()) s.pop();
            mm(instack);
            mm(paint);
            mm(dfn);
            mm(low);
            mm(indegree);
            index=1;
            col=0;
            memset(head,-1,sizeof(head));
            cnt=0;
            Ncnt=0;
        }
        void add(int a,int b,int c)
        {
            G[cnt].to=b;
            G[cnt].w=c;
            G[cnt].next=head[a];
            head[a]=cnt++;
        }
        void Nadd(int a,int b,int c)
        {
            NG[Ncnt].u=a;
            NG[Ncnt].v=b;
            NG[Ncnt++].w=c;
        }
        void Tarjan(int u)
        {
            dfn[u]=low[u]=index++;
            instack[u]=1;
            s.push(u);
            for(int i=head[u];i+1;i=G[i].next)
            {
                int v=G[i].to;
                if(!dfn[v])
                {
                    Tarjan(v);
                    low[u]=MIN(low[u],low[v]);
                }
                else if(instack[v])
                {
                    low[u]=MIN(low[u],dfn[v]);
                }
            }
            if(low[u]==dfn[u])
            {
                int k=s.top();
                while(k!=u)
                {
                    s.pop();
                    paint[k]=col;
                    instack[k]=0;
                    k=s.top();
                }
                s.pop();
                paint[u]=col;
                instack[u]=0;
                col++;
            }
        }
        void build_NG(int n)
        {
            for(int i=0;i<n;i++)
            {
                for(int j=head[i];j+1;j=G[j].next)
                {
                    int u=i,v=G[j].to;
                    if(paint[u]!=paint[v])
                    {
                        Nadd(paint[u],paint[v],G[j].w);
                    }
                }
            }
        }
}pre_deal;
__int64 directed_mst(int root,int nv,int ne)
{
    __int64 res=0;
    int in[N],pre[N];
    int id[N],vis[N];
    while(true)
    {
        //==找最小入边== 
        for(int i=0;i<nv;i++)
        {
            in[i]=INF;
        }
        for(int i=0;i<ne;i++)
        {
            int u=NG[i].u;
            int v=NG[i].v;
            if(NG[i].w<in[v]&&u!=v)
            {
                pre[v]=u;
                in[v]=NG[i].w;
            }
        }
        for(int i=0;i<nv;i++)
        {
            if(i==root) continue;
            if(in[i]==INF) return -1;
        }
        //==找有向圈==
        int cntnode=0;
        in[root]=0;
        memset(id,-1,sizeof(id));
        memset(vis,-1,sizeof(vis));
        for(int i=0;i<nv;i++)
        {
            int v=i;
            res+=in[i];
            while(vis[v]!=i&&id[v]==-1&&v!=root)
            {
                vis[v]=i;
                v=pre[v];
            }
            if(id[v]==-1&&v!=root)
            {
                for(int u=pre[v];u!=v;u=pre[u])
                {
                    id[u]=cntnode;
                }
                id[v]=cntnode++;
            }
        } 
        if(cntnode==0) break;
        for(int i=0;i<nv;i++)
        {
            if(id[i]==-1) 
            {
                id[i]=cntnode++;
            }
        }
        //==缩点,重新标记==
        for(int i=0;i<ne;i++)
        {
            int v=NG[i].v;
            NG[i].u=id[NG[i].u];
            NG[i].v=id[NG[i].v];
            if(NG[i].u!=NG[i].v)
            {
                NG[i].w-=in[v];
            }
        } 
        nv=cntnode;
        root=id[root];
    }
    return res;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int root;
        pre_deal.Init();
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            indegree[b]++;
            pre_deal.add(a,b,c);
        }
        for(int i=0;i<n;i++)
        {
            if(!dfn[i])
            pre_deal.Tarjan(i);
        }
        int nv=col--;
        pre_deal.build_NG(n);
        /*cout<<"col="<<col<<endl;
        cout<<"Ncnt="<<Ncnt<<endl;
        cout<<"------NG------"<<endl;
        for(int i=0;i<Ncnt;i++)
        {
            cout<<NG[i].u<<"-->"<<NG[i].v<<"的价值"<<NG[i].w<<endl;
        }
        cout<<"根是:"<<paint[0]<<endl;*/ 
        for(int i=0;i<n;i++)
        {
            if(indegree[i]==0)
            {
                root=i;
                break;
            }
        }
        __int64 ans=directed_mst(paint[root],nv,Ncnt);
        printf("%I64d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(HDU 3072 Intelligence System 传递的最小费用)