最小树形图

来源:互联网 发布:会声会影x9激活软件 编辑:程序博客网 时间:2024/06/05 21:49

最小树形定义:在向图中,通过某一个定点v,能访问到所有其它点,且使权值和最小。

本文介绍的算法叫朱刘算法,是由两位中国人朱永津,刘振宏在1965所发明。算法的核心思想是除了定点外,每个点必有一条入边,贪心及缩点。它的步骤是:

step1:从v点出发,检测是否能访问所有顶点。能,执行step2;否则不存在最小树形图,返回。

step2:对于除定点v之外的所有点,找出它的最小入边pre[i]及其权值in[i];

step3:对于step2找出的所有边,检测是否存在环,不存在,则最小权值和为sum{in[i]},1 <= i <= vertex(点的总和),返回;否则,执行step4;

step4:将环上的点缩成一个新点,用这个新点代替原来环上所有的点。而对于所有的点i,修改其入边值costi = costi - in[i];返回step2。

模板是根据hh的改的http://www.notonlysuccess.com/index.php/mst/

struct Graph{#define N 101#define M 10001#define INF 100000000int vertex,edge;int head[N];struct Node{//u --> vint u;int v;int next;int cost;Node(){};Node(int a,int b,int c,int d):u(a),v(b),next(c),cost(d){};}adjlist[M];//valuables min_tree needsint visited[N];int in[N],pre[N],color[N];int mincost,count;void init(int n){memset(head,-1,sizeof(head));vertex = n;edge = 0;}void insert(int u,int v,int w){adjlist[edge] = Node(u,v,head[u],w);head[u] = edge++;}int min_tree(int root){//检测从根能否遍历整个图memset(visited,0,sizeof(visited));check(root);for(int i = 1;i <= vertex;i++)if(!visited[i])return -1;mincost = 0;while(1){//更新最小入边for(int i = 1;i <= vertex;i++)in[i] = INF;for(int i = 0;i < edge;i++){int u = adjlist[i].u;int v = adjlist[i].v;int w = adjlist[i].cost;if(in[v] > w && u != v) //u != v{in[v] = w;pre[v] = u;}}//查环count = 0;in[root] = 0;memset(visited,0,sizeof(visited));memset(color,0,sizeof(color));color[root] = ++count;for(int i = 1;i <= vertex;i++){mincost += in[i];int v = i;while(visited[v] != i && !color[v]){visited[v] = i;v = pre[v];}//对环染色if(!color[v]){//注意,这里v是环上的点,但i不一定是color[v] = ++count;for(int u = pre[v];u != v;u = pre[u])color[u] = count;}}//无环if(count == 1)return mincost;//非环上的点重新设编号for(int i = 1;i <= vertex;i++)if(!color[i])color[i] = ++count;//缩点for(int i = 0;i < edge;i++){int u = adjlist[i].u;int v = adjlist[i].v;adjlist[i].u = color[u];adjlist[i].v = color[v];if(color[u] != color[v])adjlist[i].cost -= in[v];}vertex = count;root = color[root];}return -1;}void check(int x){visited[x] = 1;for(int i = head[x];i != -1;i = adjlist[i].next){int v = adjlist[i].v;if(!visited[v])check(v);}}}g;
这是定根的,如果不定根的话,我们可以加一个虚拟结点,它到每个点加一个边,权值为所有权值和 + 1或者更大,设其为INF。在最后返回判断的时候,min - INF < INF,则图产有生成树有权值和最小为min - INF;否则,没有生成树。不定根的时候,我们可以知道,因为新增的点到所有点都有边,所以可以略去step1。

另外,不定根输出定点的时候,可以在结构体Node里面加两个属性realu,realv,表示它实际的点,而我们计算的时候(比如缩点)用的则u和v。

原创粉丝点击