jobdu-1447-最短路

问题

题目:[jobbu-1447]

思路(dijkstra)

DIJKSTRA( G, w, s ){
    1.INITIALIZE-SINGLE-SOURCE(G,s)
    2.S = EMPTY
    3.Q = V[G];
    4.while Q!=EMPTY
        4.1 do u = EXTRACT-MIN(Q);
        4.2 S = S U {u};
        4.3 for each vertex v in adj[u]:
            do relax(u,v,w)
}

两个重要数据结构:

dist[i] : shortest path estimate from s to i
path[i]: shortest path from s to i
relax(u,v,w){
    if( d[u] + w < d[v] )
        d[v] = d[u] + w
}

基本思路:
基于路径长度依次递增的方式。每次从v-s当中找到距离s最近的顶点(注意,prim算法是从v-s中找到距离集合s最近的点,不是单源点s最近的点)。这个点要么是从s可以直接到达,要么是借助集合s当中的节点可以直接到达。

有个地方需要注意,上面的代码求出来的是单源点s到所有点的最短距离。如果只是求出s到t的最短路,那么在将t加入到SET S当中的时候可以判断,满足条件就返回了。

代码

#include <iostream>
#include <vector>
#include <climits>
#include <string.h>
#define N 100 + 8

struct Edge {
    int node;
    int cost;

    Edge() : node(0), cost(0) {}
    Edge( int n, int c ) : node(n), cost(c) {}
};

typedef std::vector<Edge> EdgeList;
EdgeList adj_list[N];

int d[N]; // shortest path estimate from s to i;
int flag[N]; // set v , flag[i] = 1 means it is reachable form s to i

int dijk( EdgeList* adj_list, int n, int s, int t );
void relax( int u, int v, int w );

int main(){
    int n,m;
    while( std::cin >> n >> m ){
        if( 0==n && 0==m ) break;

        for( int i = 0; i < N; ++i ) adj_list[i].clear();

        // input m edges
        for( int i = 0; i < m; ++i ){
            int u,v,w;
            std::cin >> u >> v >> w;

            Edge edge(v, w);
            adj_list[u].push_back(edge);

            Edge edge1( u, w );
            adj_list[v].push_back(edge1);
        }

        // cal the dist
        int ans = dijk( adj_list, n, 1, n );
        std::cout << ans << std::endl;
    }
    return 0;
}

int dijk( EdgeList* adj_list, int n, int s, int t ){
    for( int i = 1; i <=n ; ++i ){
        d[i] = INT_MAX;
    }
    d[s] = 0;

    memset(flag, 0, sizeof(flag));


    int cnt = n;
    while( cnt-- ){
        // select u
        int min_dist = INT_MAX;
        int u = -1;
        for( int i = 1; i <= n; ++i ){
            if( flag[i] ) continue;
            else{
                if( d[i] < min_dist ){
                    u = i;
                    min_dist = d[i];
                }
            }
        }

        // add u to set s
        d[u] = min_dist;
        flag[u] = 1;
        if( u == t ) return d[u];

        // relax (u,v,w)
        int sz = adj_list[u].size();
        for( int j = 0; j < sz; ++j ){
            int v = adj_list[u][j].node;
            int w = adj_list[u][j].cost;
            relax( u, v, w );
        }
    }
}
void relax( int u, int v, int w ){
    if( d[u] + w < d[v] )
        d[v] = d[u] + w;
}

思路(bellman-ford)

我就说一句,bellman-ford遇见负环的情况失败。这是因为存在负环就不存在最短距离。但是它可以求有负边的情形。但是,dijkstra算法没有办法求存在负边的情形。因为他是路径长度依次递增的算法!存在负边与他的思路矛盾。

代码

#include <iostream>
#include <vector>
#include <string.h>
#include <limits.h>
#define N 108

struct Edge{
    int node;
    int weight;
    Edge(){ memset( this, 0, sizeof(Edge) ) ; }
    Edge( int n, int w ) : node(n), weight(w) {}
};

typedef std::vector<Edge> EdgeList;
EdgeList adj_list[N];
int d[N];

void init(){
    for( int i = 0; i < N; ++i ){
        adj_list[i].clear();
    }
}

int bellman_ford( int n, int s, int t );

int main( void ){
    int n, m;
    while( std::cin >> n >> m ){
        if( !n && !m ) break;
        init();
        for( int i = 0; i < m; ++i ) {
            int u, v, w;
            std::cin >> u >> v >> w;
            Edge edge( v, w );
            adj_list[u].push_back(edge);

            Edge edge1(u, w);
            adj_list[v].push_back(edge1);
        }

        int ans = bellman_ford( n, 1, n );
        std::cout << ans << std::endl;
    }
    return 0;
}

int bellman_ford( int n, int s, int t ){
    // init
    for( int i = 1; i <= n; ++i ){
        d[i] = INT_MAX;
    }
    d[s] = 0;

    // V-1 pass
    for( int k = 1; k < n; ++k ){
        // relax each edge
        for( int u = 1; u <= n; ++u ){
            int sz = adj_list[u].size();
            for( int j = 0; j < sz; ++j ){
                int v = adj_list[u][j].node;
                int w = adj_list[u][j].weight;
                if( d[u] + w < d[v] )
                    d[v] = d[u] + w;
            }
        }
    }

    // test nagative cycle
    for( int u = 1; u <= n; ++u ){
        int sz = adj_list[u].size();
        for( int j = 0; j < sz; ++j ){
            int v = adj_list[u][j].node;
            int w = adj_list[u][j].weight;
            if( d[u] + w < d[v] )
                return -1;
        }
    }
    return d[t];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值