Luogu4716【模板】最小树形图

Luogu4716【模板】最小树形图

题面:洛谷

解析

没啥好讲的,模板而已,算法也很好理解。
ps:博主终于把这个咕了n久的算法学了虽然过一段时间就会忘掉

代码


// luogu-judger-enable-o2
#include<cstdio>
#define N 105
#define M 10005
using namespace std;
const int INF=1e9;
int n,m,root,_in[N],pre[N],vis[N],id[N];
#define gc() getchar()
inline int In(){
    char c=gc(); int x=0,ft=1;
    for(;c<'0'||c>'9';c=gc()) if(c=='-') ft=-1;
    for(;c>='0'&&c<='9';c=gc()) x=x*10+c-'0';
    return x*ft;
}
int h[N],e_eot=0;
struct E{ int u,v,w; }e[M];
int Solve(){
    int ans=0,cnt;
    while(1){
        for(int i=1;i<=n;++i) _in[i]=INF;
        for(int i=1;i<=m;++i){
            int u=e[i].u,v=e[i].v;
            if(u!=v&&e[i].w<_in[v]) _in[v]=e[i].w,pre[v]=u;
        }
        for(int i=1;i<=n;++i) if(i!=root&&_in[i]==INF) return -1;
        cnt=0; for(int i=1;i<=n;++i) vis[i]=id[i]=0;
        for(int i=1;i<=n;++i){
            if(i==root) continue;
            ans+=_in[i]; int v=i;
            while(vis[v]!=i&&!id[v]&&v!=root){
                vis[v]=i; v=pre[v];
            }
            if(!id[v]&&v!=root){
                id[v]=++cnt;
                for(int u=pre[v];u!=v;u=pre[u]) id[u]=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){
            int u=e[i].u,v=e[i].v;
            e[i].u=id[u]; e[i].v=id[v];
            if(id[u]!=id[v]) e[i].w-=_in[v];
        }
        root=id[root]; n=cnt;
    }
    return ans;
}
int main(){
    n=In(); m=In(); root=In();
    for(int i=1;i<=m;++i) e[i]=(E){In(),In(),In()};
    printf("%d\n",Solve());
    return 0;
}

posted @ 2019-03-14 21:59  pkh68  阅读(115)  评论(0编辑  收藏  举报