最小树形图

来源:互联网 发布:知道mac地址怎么查ip 编辑:程序博客网 时间:2024/06/03 20:12

最小树形图:即有向图的最小生成树。

最小树形图的第一个算法是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法。

有向图的最小生成树与无向图的最小生成树的区别:对于无向图,只要该图的最小生成树存在,那么无论以哪个点为根,一定可以找到其最小生成树;而对于有向图来说,可能从某一个顶点为根开始找最小生成树是存在的,而从另一个点为根来找却不能找到一个最小生成树。

最小树形图问题的分类:一般分为两类,有定根的最小树形图和无定根的最小树形图。有定根最小树形图就是题目给出谁是固定的根,然后从这个固定的根开始找一颗最小生成树,不定根最小树形图,题目不给出固定的根,让你求一棵最小生成树。

最小树形图的求解:不论是有定根还是无定根,其求解的步骤都是相同的,唯一不同的是求不定根最小树形图我们需要建立虚根,并添加多余的边。在此我们求解最小树形图的采用的方法是国产算法,朱刘算法,其他求解方法有tarjan。

图1

求解步骤:
(1) 先求出每个顶点的最小入边权,如果图无环,且入度为0的顶点至多有一个,则最小树形图就是所有最小入边权的和。如果入度为0的点多余1个,则不存在最小树形图,算法结束,若存在有向环则继续执行步骤2。
(2) 如果存在有向环,把位于一个环中的点缩成一个节点,并对图中所有节点进行重新编号,且对新图的边进行更新。形成新图,
(3) 重复步骤(1),(2)直到图中无环,算法结束,答案是每一次循环中所有点的最小入边权累加结果即为答案。

代码:

int Directed_MST(int root,int V,int E){//传入的参数分别为根节点,顶点数目,边数目    int ans=0;    int u,v;    while(1)    {        for(int i=0; i<=V; i++)            minIn[i]=INF;///minIn存放i节点的最小入边权        for(int i=0; i<E; i++)        {///找最小入边权            u=edge[i].u;            v=edge[i].v;            if(minIn[v]>edge[i].w&&u!=v)            {                minIn[v]=edge[i].w;                pre[v]=u;                if(u==root)                    pos=i;            }        }        for(int i=0; i<V; i++)        {///如果存在root以外的孤立点,则不存在最小树形图            if(i==root)continue;            if(minIn[i]==INF) return -1;        }        memset(vis,-1,sizeof(vis));        memset(id,-1,sizeof(id));///id[i]存放节点i的新编号        int cnt=0;        minIn[root]=0;        for(int i=0; i<V; i++)        {            ans+=minIn[i];            v=i;            while(vis[v]!=i&&id[v]==-1&&v!=root)            {///判是否有环,有环回到自身,无环的话就会回到根                vis[v]=i;                v=pre[v];            }            if(id[v]==-1&&v!=root)            {///有环,把环中的编号都赋为一样                for(u=pre[v]; u!=v; u=pre[u])                    id[u]=cnt;                id[v]=cnt++;            }        }        if(cnt==0) break;        for(int i=0; i<V; i++)            if(id[i]==-1)            id[i]=cnt++;///标记孤立点        for(int i=0; i<E; i++)        {            u=edge[i].u;            v=edge[i].v;            edge[i].u=id[u];            edge[i].v=id[v];            if(id[u]!=id[v])            {///不在一个环中                edge[i].w-=minIn[v];            }        }        V=cnt;        root=id[root];    }    return ans;}
原创粉丝点击