hdu 3072 强连通+缩点+最小树形图思想

#include<stdio.h>
#include<string.h>
#define N 51000
#define inf 1000000000
struct node {
    int u,v,w,next;
}bian[N*2];
int dfn[N],low[N],yong,index,ans[N],visit[N],head[N],stac[N],top,num,n;
void init() {
       yong=0;index=0;top=0;num=0;
        memset(head,-1,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(visit,0,sizeof(visit));
        memset(stac,0,sizeof(stac));
        memset(ans,0,sizeof(ans));
}
void addedge(int u,int v,int w) {
    bian[yong].u=u;
    bian[yong].v=v;
    bian[yong].w=w;
    bian[yong].next=head[u];
    head[u]=yong++;
}
int min(int a,int b) {
    return a>b?b:a;
}
void tarjan(int u) {//求缩点
    int i;
    dfn[u]=low[u]=++index;
    stac[++top]=u;
    visit[u]=1;
    for(i=head[u];i!=-1;i=bian[i].next) {
        int v=bian[i].v;
        if(!dfn[v]) {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else
            if(visit[v])
                low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]) {
        ++num;
        int t;
        do {
            t=stac[top--];
            visit[t]=0;
            ans[t]=num;
        }while(t!=u);
    }
}
int main(){
    int m,i,j,k,count,dis[N];
    while(scanf("%d%d",&n,&m)!=EOF) {
            init();
        while(m--) {
            scanf("%d%d%d",&i,&j,&k);
            addedge(i,j,k);
        }
        for(i=0;i<n;i++)
            if(!dfn[i])
                tarjan(i);
        for(i=1;i<=num;i++)
            dis[i]=inf;
        for(i=0;i<yong;i++)
          if(ans[bian[i].u]!=ans[bian[i].v]) {//找到除源点外的进入每个点的最小权值,所有最小权值的和就是要求的
              int v=ans[bian[i].v];
            if(dis[v]>bian[i].w)
                dis[v]=bian[i].w;
        }
        count=0;
        for(i=1;i<=num;i++){
        if(dis[i]<inf)
            count+=dis[i];
        }
        printf("%d
",count);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410704.html