Dijkstra 算法实现样例

样例输入:
6
0 2 5
0 3 30
1 0 2
1 4 8
2 5 7
2 1 15
4 3 4
5 3 10
5 4 18
-1 -1 -1

样例输出:


20 0->2->1
5 0->2
22 0->2->5->3
28 0->2->1->4
12 0->2->5

 

 

#include <stdio.h>
#include <string.h>
#define INF    1000000    //无穷大
#define MAXN 20        //顶点个数的最大值

int n;                //顶点个数
int Edge[MAXN][MAXN];    //邻接矩阵
int S[MAXN];        //Dijkstra算法用到的3个数组
int dist[MAXN];        //
int path[MAXN];        //

void Dijkstra( int v0 )    //求顶点v0到其他顶点的最短路径
{
    int i, j, k;    //循环变量
    for( i=0; i<n; i++ )
    {
        dist[i] = Edge[v0][i];  S[i] = 0;
        if( i!=v0 && dist[i]<INF )  path[i] = v0;
        else path[i] = -1;
    }
    S[v0] = 1;  dist[v0] = 0;    //顶点v0加入到顶点集合S
    for( i=0; i<n-1; i++ )        //从顶点v确定n-1条最短路径
    {
        int min = INF, u = v0;
        
        //选择当前集合T中具有最短路径的顶点u
        for( j=0; j<n; j++ )
        {
            if( !S[j] && dist[j]<min )
            {
                u=j;  min = dist[j];
            }
        }
        
        S[u] = 1;    //将顶点u加入到集合S,表示它的最短路径已求得
        
        for( k=0; k<n; k++ )    //修改T集合中顶点的dist和path数组元素值
        {
            if( !S[k] && Edge[u][k]<INF && dist[u] + Edge[u][k] < dist[k] )
            {
                dist[k] = dist[u] + Edge[u][k];  path[k] = u;
            }
        }
    }
}

int main( )
{
    int i, j;    //循环变量
    int u, v, w;    //边的起点和终点及权值
    scanf( "%d", &n );    //读入顶点个数n
    while( 1 )
    {
        scanf( "%d%d%d", &u, &v, &w );    //读入边的起点和终点
        if( u==-1 && v==-1 && w==-1 )  break;
        Edge[u][v] = w;    //构造邻接矩阵
    }
    for( i=0; i<n; i++ )
    {
        for( j=0; j<n; j++ )
        {
            if( i==j ) Edge[i][j] = 0;
            else if( Edge[i][j]==0 )  Edge[i][j] = INF;
        }
    }
    Dijkstra( 0 );    //求顶点0到其他顶点的最短路径
    int shortest[MAXN];    //输出最短路径上的各个顶点时存放各个顶点的序号
    for( i=1; i<n; i++ )
    {
        printf( "%d\t", dist[i] );    //输出顶点0到顶点i的最短路径长度
        //以下代码用于输出顶点0到顶点i的最短路径
        memset( shortest, 0, sizeof(shortest) );
        int k = 0;    //k表示shortest数组中最后一个元素的下标
        shortest[k] = i;
        while( path[ shortest[k] ] != 0 )
        {
            k++; shortest[k] = path[ shortest[k-1] ];
        }
        k++; shortest[k] = 0;
        for( j=k; j>0; j-- )
            printf( "%d→", shortest[j] );
        printf( "%d\n", shortest[0] );
    }
    return 0;
}

 

 

/* Dijkstra O(E * log E)
INIT: 调用init(nv, ne)读入边并初始化;
CALL: dijkstra(n, src); dist[i]为src到i的最短距离 */
int cost[E], dist[V];
int e, pnt[E], nxt[E], head[V], prev[V], vis[V];
struct qnode {
    int v;
    int c;
    qnode(int vv = 0, int cc = 0) : v(vv), c(cc) {}
    bool operator<(const qnode & r) const {return c > r.c;}
};
void dijkstra(int n, const int src) {
    qnode mv;
    int i, j, k, pre;
    priority_queue<qnode> que;
    vis[src] = 1;
    dist[src] = 0;
    que.push(qnode(src, 0));
    for (pre = src, i = 1; i < n; i++) {
        for (j = head[pre]; j != -1; j = nxt[j]) {
            k = pnt[j];
            if (vis[k] == 0 && dist[pre] + cost[j] < dist[k]) {
                dist[k] = dist[pre] + cost[j];
                que.push(qnode(pnt[j], dist[k]));
                prev[k] = pre;
            }
        }
        while (!que.empty() && vis[que.top().v] == 1)
            que.pop();
        if (que.empty()) break;
        mv = que.top();
        que.pop();
        vis[pre = mv.v] = 1;
    }
}
inline void addedge(int u, int v, int c) {
    pnt[e] = v;
    cost[e] = c;
    nxt[e] = head[u];
    head[u] = e++;
}
void init(int nv, int ne) {
    int i, u, v;
    int c;
    e = 0;
    memset(head, -1, sizeof (head));
    memset(vis, 0, sizeof (vis));
    memset(prev, -1, sizeof (prev));
    for (i = 0; i < nv; i++) dist[i] = inf;
    for (i = 0; i < ne; ++i) {
        scanf("%d%d%d", &u, &v, &c); // %d: type of cost
        addedge(u, v, c); // vertex: 0 ~ n-1, 单向边,双向边时加两次即可
    }
}

 

转载于:https://www.cnblogs.com/Deng1185246160/p/3223025.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值