最小树形图(朱刘算法)学习笔记&板子

最小树形图朱刘算法
大概流程:
初始化答案ans=0
1.每个点 v v 选个最小入边 (u,v,prec[v]) ( u , v , p r e c [ v ] ) ,如果有点没有 prec p r e c 就无解
2. i,irootans+=prec[i] ∑ i , i ≠ r o o t a n s + = p r e c [ i ]
2.若最小入边构成的是一棵树,那这个就是答案
3.否则最小入边会构成一棵树和若干个环,建一个新图 G G ′ ,在新图中把环缩成一个点 v v ′
4.设点 x x 在新图中对应点 x x ′ ,对于原图中的一条边 (u,v,w) ( u , v , w ) ,若他在新图中不是一个自环,建边 (u,v,wprec[v]) ( u ′ , v ′ , w − p r e c [ v ] ) ,然后回到步骤1

板子
hdu2121
code:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pb push_back
#define SZ(x) (int)x.size()
#define mp make_pair
#define fir first
#define sec second
using namespace std;

const int maxn = 11000;
const int maxm = 11000;

ll ans,sum; int root;
int n,m;
struct node
{
    int ty,y; ll c;
    node(){}
    node(int _ty,int _y,ll _c){ty=_ty,y=_y,c=_c;}
};
vectorG[maxn],nG[maxn];
ll pc[maxn];
int pi[maxn],pv[maxn];

void init()
{
    ans=0,sum=0;
    for(int i=1;i<=n+1;i++) G[i].clear(),nG[i].clear(),pc[i]=LLONG_MAX,pv[i]=0,pi[i]=0;
}
int id[maxn],cnt;
int vis[maxn];
int solve(int rt)
{
    while(1)
    {
        for(int i=1;i<=n;i++) if(i!=rt&&!pv[i]) return 0;
        for(int i=1;i<=n;i++) ans+=pc[i];

        int cir=0; cnt=0;
        for(int i=1;i<=n;i++) vis[i]=0,id[i]=0;
        vis[rt]=-1;
        for(int i=1;i<=n;i++)
        {
            int u;
            for(u=i;!vis[u];u=pv[u]) vis[u]=i;
            if(vis[u]==i)
            {
                cir=1;
                id[u]=++cnt;
                for(int v=pv[u];v!=u;v=pv[v]) id[v]=cnt;
            }
        }
        for(int i=1;i<=n;i++) if(!id[i]) id[i]=++cnt;
        if(!cir)
        {
            for(int i=1;i<=n;i++) if(i!=rt&&pv[i]==rt) root=pi[i];
            return ans<2*sum;
        }

        for(int i=1;i<=cnt;i++) nG[i].clear();
        for(int i=1;i<=n;i++)
        {
            for(int j=0;jint y=G[i][j].y; ll c=G[i][j].c-pc[y];
                if(id[i]==id[y]) continue;
                nG[id[i]].pb(node(G[i][j].ty,id[y],c));
            }
        }
        n=cnt;
        for(int i=1;i<=n;i++) pc[i]=LLONG_MAX,pi[i]=pv[i]=0;
        for(int i=1;i<=n;i++)
        {
            G[i].clear();
            for(int j=0;jint y=G[i][j].y; ll c=G[i][j].c;
                if(c0;
    }
}

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int x,y;ll c; scanf("%d%d%lld",&x,&y,&c);
            x++,y++;
            if(x==y) continue;
            G[x].pb(node(y,y,c));
            sum+=c;
            if(pc[y]>c) pc[y]=c,pv[y]=x,pi[y]=y;
        }
        sum++;
        for(int i=1;i<=n;i++)
        {
            G[n+1].pb(node(i,i,sum));
            if(pc[i]>sum) pc[i]=sum,pv[i]=n+1,pi[i]=i;
        }
        pc[++n]=0;
        if(!solve(n)) puts("impossible");
        else printf("%lld %d\n",ans-sum,root-1);
        putchar('\n');
    }

    return 0;
}

你可能感兴趣的:(板子,乱七八糟的东西)