某种带权有向无环图(graph)的所有路径的求法
// 讨论QQ群:135202158
最近做某个东西,最后用图实现了,这里总结一下算法。
假设有以下带权有向无环图(连通或非连通,我这里用的是非连通的):
每个节点(node)可能与其他节点有向地相连,相邻节点的边(edge)有权值(weight)属性。从一个节点到任意一个节点的连的集合称为路径(path),且路径的权为各边权的最小值。
现在的问题就是求所有可能的路径,并算出各路径的权。
以下是简单的C++代码实现,我是用遍历边来实现的,节点和边是两个数据结构:
1 #include <iostream> 2 #include <vector> 3 #include <list> 4 5 using namespace std; 6 7 // 节点 8 struct node 9 { 10 char val; 11 12 node(char c) : val(c) {} 13 }; 14 15 // 边 16 struct edge 17 { 18 // a->b,w为权 19 node a; 20 node b; 21 int w; 22 23 edge(node& _a, node& _b, int _w) : a(_a), b(_b), w(_w) {} 24 }; 25 26 // 遍历各边时所有的记录 27 struct record 28 { 29 list<node> path; // 路径上的节点列表 30 list<int> ws; // 当前的最小权列表 31 }; 32 33 // 生成上图所示带权有向无环图 34 void gen_samples(vector<node>& nodes, vector<edge>& edges); 35 36 37 // 递归遍历 38 void travel_path(vector<edge>& edges, edge& x, record& r) 39 { 40 size_t i; 41 for(i=0; i<edges.size(); ++i) 42 { 43 edge e = edges[i]; 44 // 判断是否连通 45 if(x.b.val == edges[i].a.val) 46 { 47 r.path.push_back(edges[i].b); 48 int w = min(x.w, edges[i].w); 49 r.ws.push_back(w); 50 travel_path(edges, edges[i], r); 51 } 52 } 53 54 // 不与任何节点有向连通,输出路径,并回溯至上个节点 55 if(i == edges.size()) 56 { 57 for(list<node>::iterator it = r.path.begin(); 58 it != r.path.end(); ++it) 59 cout << it->val << " "; 60 cout << ", " << r.ws.back() << endl; 61 62 r.path.pop_back(); 63 r.ws.pop_back(); 64 } 65 } 66 67 68 int main() 69 { 70 vector<node> nodes; 71 vector<edge> edges; 72 73 gen_samples(nodes, edges); 74 75 for(size_t i=0; i<edges.size(); ++i) 76 { 77 record r; 78 r.path.push_back(edges[i].a); 79 r.path.push_back(edges[i].b); 80 r.ws.push_back(edges[i].w); 81 82 travel_path(edges, edges[i], r); 83 } 84 85 system("PAUSE"); 86 return 0; 87 } 88 89 90 91 void gen_samples(vector<node>& nodes, vector<edge>& edges) 92 { 93 node a('A'); nodes.push_back(a); 94 node b('B'); nodes.push_back(b); 95 node c('C'); nodes.push_back(c); 96 node d('D'); nodes.push_back(d); 97 node e('E'); nodes.push_back(e); 98 node f('F'); nodes.push_back(f); 99 node g('G'); nodes.push_back(g); 100 node h('H'); nodes.push_back(h); 101 node i('I'); nodes.push_back(i); 102 node j('J'); nodes.push_back(j); 103 node k('K'); nodes.push_back(k); 104 105 edge e1(a, c, 5); edges.push_back(e1); 106 edge e2(b, d, 2); edges.push_back(e2); 107 edge e3(b, e, 7); edges.push_back(e3); 108 edge e4(c, f, 4); edges.push_back(e4); 109 edge e5(c, h, 1); edges.push_back(e5); 110 edge e6(e, h, 5); edges.push_back(e6); 111 edge e7(g, i, 2); edges.push_back(e7); 112 edge e8(g, j, 8); edges.push_back(e8); 113 edge e9(h, k, 3); edges.push_back(e9); 114 }
执行结果为(逗号前面是沿路径的各节点,后面的数字是路径的权):
A C F , 4 A C H K , 1 A C H , 1 A C , 5 B D , 2 B E H K , 3 B E H , 5 B E , 7 C F , 4 C H K , 1 C H , 1 E H K , 3 E H , 5 G I , 2 G J , 8 H K , 3
出来的结果是所有可能的路径,如果要找包含某节点的最长路径的话,这个是有冗余的,需要去一下。