某种带权有向无环图(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


出来的结果是所有可能的路径,如果要找包含某节点的最长路径的话,这个是有冗余的,需要去一下。

 

posted @ 2013-07-21 19:07  赵子清  阅读(2494)  评论(0编辑  收藏  举报