最小树形图模板

//有定根模板
板子:

/** @Cain*/
int a[maxn][maxn];
int in[maxn],pre[maxn],vis[maxn],id[maxn];
int dirTree(int root,int n,int m)
{   //root为根的编号, n个点, m条边.
    int res = 0;
    while(1){
        for(int i=0;ifor(int i=0;iint u = s[i].u;
            int v = s[i].v;
            int w = s[i].w;
            if(w < in[v] && u != v){
                in[v] = w;
                pre[v] = u;
            }
        }
        in[root] = 0;
        for(int i=0;iif(in[i] != inf)
                res += in[i];
            else return -1;
        }
        pre[root] = root;
        int newid = 0;
        memset(vis,-1,sizeof(vis));
        memset(id,-1,sizeof(id));
        for(int i=0;iint u = i;
            while(vis[u] != i && id[u] == -1){
                vis[u] = i;
                u = pre[u];
            }
            if(u == root || vis[u] != i) continue;
            for(int v = pre[u] ; v != u ; v = pre[v] )
                id[v] = newid;
            id[u] = newid++;
        }
        if(newid == 0) break;
        for(int i=0;iif(id[i] == -1)
                id[i] = newid++;
        }
        for(int i=0;i.w -= in[s[i].v];
            s[i].u = id[s[i].u];
            s[i].v = id[s[i].v];
        }
        root = id[root];
        n = newid;
    }
    return res;
}

解释版:

/** @Cain*/
int a[maxn][maxn];
int in[maxn],pre[maxn],vis[maxn],id[maxn];
int dirTree(int root,int n,int m)
{   //root为根的编号, n个点, m条边.
    int res = 0;
    while(1){
        for(int i=0;ifor(int i=0;iint u = s[i].u;
            int v = s[i].v;
            int w = s[i].w;
            if(w < in[v] && u != v){  //找每个点入度最小的那条边,同时记录父亲.
                in[v] = w;
                pre[v] = u;
            }
        }
        in[root] = 0;
        for(int i=0;iif(in[i] != inf)
                res += in[i];   //此时加的是第一次最优情况下的最小差值.
            else return -1;     //图不联通.
        }
        pre[root] = root;
        int newid = 0;
        memset(vis,-1,sizeof(vis));
        memset(id,-1,sizeof(id));
        for(int i=0;i//缩点操作.
            int u = i;
            while(vis[u] != i && id[u] == -1){
                vis[u] = i;
                u = pre[u];
            }
            if(u == root || vis[u] != i) continue;
            for(int v = pre[u] ; v != u ; v = pre[v] )
                id[v] = newid;
            id[u] = newid++;
        }
        if(newid == 0) break;
        for(int i=0;iif(id[i] == -1)
                id[i] = newid++;
        }
        for(int i=0;i//更新边的操作. 原先选了的边变成0,是不影响下次我们选择的.
            s[i].w -= in[s[i].v];
            s[i].u = id[s[i].u];
            s[i].v = id[s[i].v];
        }
        root = id[root];   //root的编号变了.
        n = newid;
    }
    return res;
}

//对于无定根的, 一般是让你去找那个点作为根合适. 这种题我们知道进行n(节点个数)次最小树形图, 可以找出来, 但是时间不允许. 所以我们引出虚根的概念. 虚根到每一个实际的点的权值是什么要看题目. 如果是单纯求那个点作为根合适的, 就把虚边令成inf, 所以在找入边时, 顺便记下是哪个点连接的虚根, 那么最后就由它作为根. 并且判一下该幅图是否联通.
比如hdu2121
题解

还有一种是虚边设置为与该点有关系的值, 比如是该点所特有的性质. 这样跑一次最小树形图就可以直接出最优答案.
比如hdu – 4009
题解

你可能感兴趣的:(最小树形图)