【算法笔记】最短路总结

来源:互联网 发布:python实现朴素贝叶斯 编辑:程序博客网 时间:2024/06/06 06:31

次短路

目前只会用dijstra求解。。(貌似有用spfa的。。
当然如果是DAG, 拓扑排序加DP也是可以的。。

次短路的求解和计数

hdu 3191

这道题有边权为0的情况。
dij所使用的贪心性质:S是目标集合(已经求得最短路或次短路的点),从 V - S 中选估计值最小的一个u,那么d[u]就是u的最短路长度。
如果边权有0存在, 那么这条性质就无法保证了。。
幸而数据比较特殊, 只要保证编号小的点先更新就行了。。

// 这道题的数据里面有权值为0的情况,pq并不能保证正确// 详见 http://acm.hdu.edu.cn/discuss/problem/list.php?problemid=3191int n, m, src, dst;struct Edge {    int v, w;};vector<Edge> graph[N];struct Node {    int flag, d, i;    bool operator < (const Node &rhs) const {        if ( d != rhs.d ) return d > rhs.d;        return i > rhs.i;    }};const int INF = 1e9;int d[2][N], cnt[2][N];bool done[2][N];void dij() {    memset(done, 0, sizeof(done));    memset(cnt, 0, sizeof(cnt));    fill(d[0], d[0] + n, INF);    fill(d[1], d[1] + n, INF);    d[0][src] = 0;    cnt[0][src] = 1;    d[1][src] = -1;    priority_queue<Node> q;    q.push( (Node) {0, 0, src} );    while(!q.empty()) {        Node fr = q.top(); q.pop();        int u = fr.i, du = fr.d;        if ( done[fr.flag][u] ) continue;        done[fr.flag][u] = 1;        for (int i = 0; i < graph[u].size(); ++i) {            int v = graph[u][i].v, w = du + graph[u][i].w, num = cnt[fr.flag][u];            if ( d[0][v] > w ) {                if ( d[0][v] != INF ) {                    d[1][v] = d[0][v];                    cnt[1][v] = cnt[0][v];                    q.push( (Node) {1, d[1][v], v} );                }                d[0][v] = w;                cnt[0][v] = num;                q.push( (Node) {0, d[0][v], v} );            } else if ( !done[0][v] && d[0][v] == w ) {                cnt[0][v] += num;            } else if ( d[1][v] > w ) {                cnt[1][v] = num;                d[1][v] = w;                q.push( (Node) {1, d[1][v], v} );            } else if ( !done[1][v] && d[1][v] == w ) {                cnt[1][v] += num;            }        }    }    printf("%d %d\n", d[1][dst], cnt[1][dst]);}int main() {#ifdef _LOCA_ENV_    freopen("input.in", "r", stdin);#endif // _LOCA_ENV    while ( scanf("%d%d%d%d", &n, &m, &src, &dst) != EOF ) {        rep(i, 0, n-1) graph[i].clear();        rep(i, 1, m) {            int x, y, w;            scanf("%d%d%d", &x, &y, &w);            graph[x].push_back( (Edge) {y, w} );        }        dij();    }    return 0;}

次短路拓展

lightoj 1099

求无向图上次短路值, 可以往回走。。
因为是无向图, 所以往回走并不影响什么。。
只要“往回走”得到的次短路比较优, 贪心性质一定会保证它被选中。
也可以不用done数组, 直接用值比较来判断这个点是否已经用来更新过了。。

int n, m, src, dst;struct Edge {    int v, w;};vector<Edge> graph[N];struct Node {    int flag, d, i;    bool operator < (const Node &rhs) const {        if ( d != rhs.d ) return d > rhs.d;        return i > rhs.i;    }};const int INF = 1e9;int d[2][N];bool done[2][N];void dij() {    memset(done, 0, sizeof(done));    fill(d[0], d[0] + n, INF);    fill(d[1], d[1] + n, INF);    d[0][src] = 0;    d[1][src] = INF;    priority_queue<Node> q;    q.push( (Node) {0, 0, src} );    while(!q.empty()) {        Node fr = q.top(); q.pop();        int u = fr.i, du = fr.d;        if ( done[fr.flag][u] ) continue;        done[fr.flag][u] = 1;        for (int i = 0; i < graph[u].size(); ++i) {            int v = graph[u][i].v, w = du + graph[u][i].w;            if ( d[0][v] > w ) {                if ( d[0][v] != INF ) {                    d[1][v] = d[0][v];                    q.push( (Node) {1, d[1][v], v} );                }                d[0][v] = w;                q.push( (Node) {0, d[0][v], v} );            }  else if ( d[0][v] == w ) {                // pass            }  else if ( d[1][v] > w ) {                d[1][v] = w;                q.push( (Node) {1, d[1][v], v} );            }        }    }}

Dijstra拓展

当最短路径有多条的时候, 我们可以倒过来递推出, 所有最短路径。
还可以对pq使用的HeapNode节点添加一些性质, 在不影响最短路值的情况下, 决定优先用哪些边来更新。

codeforces 449B - Jzzhu and Cities

在不影响1到各点最短路值的情况下, 尽量去掉 给定边集里面的边。

0 0