最小树形图:朱刘算法
Posted st-lovaer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小树形图:朱刘算法相关的知识,希望对你有一定的参考价值。
给一个有向图,求最小树形图的权值。
用in存图,用pre记录前驱节点。
1 #include<iostream> 2 using namespace std; 3 #include<cstdio> 4 #include<cstring> 5 #define MAXN 1005 6 #define INF 0x7f7f7f7f 7 typedef __int64 type; 8 struct node//边的权和顶点 9 { 10 int u, v; 11 type w; 12 }edge[MAXN * MAXN]; 13 int pre[MAXN], id[MAXN], vis[MAXN], n, m, pos; 14 type in[MAXN];//存最小入边权,pre[v]为该边的起点 15 type Directed_MST(int root, int V, int E) 16 { 17 type ret = 0;//存最小树形图总权值 18 while(true) 19 { 20 int i; 21 //1.找每个节点的最小入边 22 for( i = 0; i < V; i++) 23 in[i] = INF;//初始化为无穷大 24 for( i = 0; i < E; i++)//遍历每条边 25 { 26 int u = edge[i].u; 27 int v = edge[i].v; 28 if(edge[i].w < in[v] && u != v)//说明顶点v有条权值较小的入边 记录之 29 { 30 pre[v] = u;//节点u指向v 31 in[v] = edge[i].w;//最小入边 32 if(u == root)//这个点就是实际的起点 33 pos = i; 34 } 35 } 36 for( i = 0; i < V; i++)//判断是否存在最小树形图 37 { 38 if(i == root) 39 continue; 40 if(in[i] == INF) 41 return -1;//除了根以外有点没有入边,则根无法到达它 说明它是独立的点 一定不能构成树形图 42 } 43 //2.找环 44 int cnt = 0;//记录环数 45 memset(id, -1, sizeof(id)); 46 memset(vis, -1, sizeof(vis)); 47 in[root] = 0; 48 for( i = 0; i < V; i++) //标记每个环 49 { 50 ret += in[i];//记录权值 51 int v = i; 52 while(vis[v] != i && id[v] == -1 && v != root) 53 { 54 vis[v] = i; 55 v = pre[v]; 56 } 57 if(v != root && id[v] == -1) 58 { 59 for(int u = pre[v]; u != v; u = pre[u]) 60 id[u] = cnt;//标记节点u为第几个环 61 id[v] = cnt++; 62 } 63 } 64 if(cnt == 0) 65 break; //无环 则break 66 for( i = 0; i < V; i++) 67 if(id[i] == -1) 68 id[i] = cnt++; 69 //3.建立新图 缩点,重新标记 70 for( i = 0; i < E; i++) 71 { 72 int u = edge[i].u; 73 int v = edge[i].v; 74 edge[i].u = id[u]; 75 edge[i].v = id[v]; 76 if(id[u] != id[v]) 77 edge[i].w -= in[v]; 78 } 79 V = cnt; 80 root = id[root]; 81 } 82 return ret; 83 } 84 int main() 85 { 86 int i; 87 while(scanf("%d%d", &n, &m) != EOF) 88 { 89 type sum = 0; 90 for( i = 0; i < m; i++) 91 { 92 scanf("%d%d%I64d", &edge[i].u, &edge[i].v, &edge[i].w); 93 edge[i].u++; edge[i].v++; 94 sum += edge[i].w; 95 } 96 sum ++; 97 for( i = m; i < m + n; i++)//增加超级节点0,节点0到其余各个节点的边权相同(此题中 边权要大于原图的总边权值) 98 { 99 edge[i].u = 0; 100 edge[i].v = i - m + 1; 101 edge[i].w = sum; 102 } 103 type ans = Directed_MST(0, n + 1, m + n); 104 //n+1为总结点数,m+n为总边数 105 //ans代表以超级节点0为根的最小树形图的总权值, 106 //将ans减去sum,如果差值小于sum,说明节点0的出度只有1,说明原图是连通图 107 //如果差值>=sum,那么说明节点0的出度不止为1,说明原图不是连通图 108 if(ans == -1 || ans - sum >= sum) 109 puts("impossible"); 110 else 111 printf("%I64d %d ",ans - sum, pos - m); 112 puts(""); 113 } 114 return 0; 115 }
以上是关于最小树形图:朱刘算法的主要内容,如果未能解决你的问题,请参考以下文章