1、基本算法
我们知道DAG上一定存在拓扑排序,且若在有向图G中从顶点Vi->Vj有一条路径,则在拓扑排序中顶点Vi一定在顶点Vj之前,而因为在DAG图中没有环,所以按照DAG图的拓扑排序进行序列最短路径的更新,一定能求出最短路径。
2、基本步骤
处理顶点V时,对每条离开的边<v,u>执行松弛运算,若果<v,u>给出从源点到u的一条最短路径(经过v),则更新到u的最短路径。这个过程将检查图中每个顶点的所有路径,同时,拓扑排序确保按正确的顺序处理顶点。
4、注意事项
图必须是DAG(有向无环图),跟差分约束类似,对于多源点向单源点转化时新加入的节点可以通过特殊的预处理老避免在实际代码中加入这个节点,在DAG图上的单源最短路径的代码中,是将入度为0的节点(也就是前面所说的多源点)的d[]值设为0,其他的d值设为INF,也就是相当于虚拟节点Vs更新之后的结果。
伪代码:
(1)初始化,入度为0的节点d为0,其他的节点d值为INF。
(2)对DAG进行拓扑排序,得到拓扑序列。
(3)按照拓扑序列遍历DAG的点,对于每个点u,遍历其所有的出边<u,v>,如果d[v] > d[v] + length<u,v>,则更新。
预处理:
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <queue> using namespace std; const int MAXN = 100010; const int MAXM = 1000010; const int INF = 0x3f3f3f3f; struct Edge { int v, w; int next; }edge[MAXM]; int n, m; int cnt, tot; int count2; int d[MAXN]; int first[MAXN]; int fa[MAXN], topo[MAXN]; int ind[MAXN], outd[MAXN]; void init() { cnt = 0; tot = 0; memset(first, -1, sizeof(first)); memset(fa, 0, sizeof(fa)); memset(ind, 0, sizeof(0)); memset(outd, 0, sizeof(outd)); } void read_graph(int u, int v, int w) { edge[cnt].v = v, edge[cnt].w = w; edge[cnt].next = first[u], first[u] = cnt++; }
toposort:
void toposort() //toposort { queue<int> q; for(int i = 1; i <= n; i++) if(!ind[i]) q.push(i); while(!q.empty()) { int x = q.front(); q.pop(); topo[++tot] = x; for(int e = first[x]; e != -1; e = edge[e].next) { int v = edge[e].v; if(--ind[v] == 0) { q.push(v); } } } }
DAGShortestpath:
void DAGShortestPath(int src) //DAG有向无环图的最短路径 { for(int i = 1; i <= n; i++) if(!ind[i]) d[i] = 0; else d[i] = INF; d[src] = 0; for(int u = 1; u <= tot; u++) { int x = topo[u]; for(int e = first[x]; e != -1; e = edge[e].next) { int v = edge[e].v, w = edge[e].w; if(d[v] > d[x] + w) { d[v] = d[x] + w; fa[v] = u; } } } }练习参考题:POJ 3249 Test for job