Dijkstr 算法 求单源最小路径

Dijkstra 算法 与 prim算法 求解最小生成树 有点类似 ,不同的是:prime 算法 输出的是 所有点全部连通的最小路径长度 , 而 Dijikstra 求解 单源最小路径 则是求解 一个点 (单源 就是 这个意思) 到其他点的 最小路径长度, 下面 我会招贴的有 prim 算法的 代码 和 Dijkstra 算法的代码, 其中 在 更新 low【】数组 (prim) 与 dist【】数组 (Dijkstra)的值得时候 if 语句里面的比较条件 不相同 , 前者是:当mapp[pos][i] < low[i] 时 low[i] = mapp[pos][i], 更新最小值;后者是 当 dist[pos] + mapp[pos][i] < dist[i] (dist【】数组 存储 下标到 单源点 的最小距离 )时 dist[i] = dist[pos] + mapp[pos][i] , 同时 保存路径的 数组 path【】也要更新 为 path[i] = pos ;

下面 是 一组测试 数据
5 7
1 2 100
1 3 30
1 5 10
3 2 60
3 4 60
4 2 10
5 4 50
1
输出如下:
1 5 4 2 70
1 3 30
1 5 4 60
1 5 10

Dijkstra 代码 如下 :

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <stack>
using namespace std;
int mapp[110][110], dist[110], path[110];// mapp数组 存储 邻接矩阵 ;dist数组存储 下标到 单源点 的最小路径;path数组 存储 最小路径中 下标点所对应的 前面路径的末尾点 ,下标表示 下一路径的开始点
int n, m, v0;// n  表示 点的个数, m 表示 边的个数 
void Dijkstra(int v0)
{
    int i, j;
    bool *visited =(bool*)malloc(sizeof(bool)*n);// 标记数组 看 该点 是否 已经查找过

    for(i = 1; i <= n; i++)// 三个数组的初始化
    {
        if(mapp[v0][i] > 0 && i != v0)
        {
            dist[i] = mapp[v0][i];
            path[i] = v0;
        }
        else
        {
            dist[i] = INT_MAX;//  not combine with spot v0,未连接 初始位距离很大
            path[i] = -1;// represent not  have  former spot
        }
        visited[i] = false;
    }
    visited[v0] = true;// v0 点 标记 已经查找

    for(i = 1; i < n; i++)//遍历 查找 最小 路径 更新 dist 与 path 数组的值
    {
        int minn = INT_MAX;
        int pos;
        for(j = 1; j <= n; j++)
            if(visited[j] == false && minn > dist[j])
                minn = dist[j], pos = j;
        visited[pos] = true;

        for(j = 1; j <= n; j++)
            if(visited[j] == false && mapp[pos][j] > 0 && minn+mapp[pos][j] < dist[j])
                dist[j] = minn + mapp[pos][j], path[j] = pos;//更新
    }

}

void ShowPath(int v, int v0)// 此函数 输出 v 点 到 v0 点的 路径 
{
    stack<int> s;
    while(v != v0)
    {
        s.push(v);
        v = path[v];
    }
    s.push(v0);
    while(!s.empty())
    {
        cout<<s.top()<<" ";
        s.pop();
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(mapp, 0, sizeof(mapp));// 初始化 为 0 

    for(int i = 1; i <= m; i++)
    {
        int a, b, s;
        cin>>a>>b>>s;
        mapp[a][b] = s;
        mapp[b][a] = s;
    }

    cin>>v0;// 单源点 
    Dijkstra(v0);
    for(int j = 1; j <= n; j++)
    {
        if(j != v0)
        {
            ShowPath(j, v0);
            cout<<dist[j]<<endl;// 输出 其他店到 单源点的 最小路径长,
        }
    }

    return 0;
}

下面是 prim 算法 大家 可以 简单的 比较一下 不同之处;
至于具体代码如何实现,现在结合POJ1258例题解释。代码如下:

#include <stdio.h>
#include <string.h>
#define MaxInt 0x3f3f3f3f
#define N 110

int map[N][N],low[N],visited[N]; //创建map二维数组储存图表,low数组记录每2个点间最小权值,visited数组标记某点是否已访问
int n;

int prim()
{
    int i,j,pos,min,result=0;
    memset(visited,0,sizeof(visited));
    visited[1]=1;pos=1;   //从某点开始,分别标记和记录该点

    for(i=1;i<=n;i++)  //第一次给low数组赋值
        if(i!=pos) low[i]=map[pos][i];

    for(i=1;i<n;i++)   //再运行n-1次
    {
     min=MaxInt;
     for(j=1;j<=n;j++)  //找出最小权值并记录位置
         if(visited[j]==0&&min>low[j])
         {
             min=low[j];pos=j;
         }

    result+=min;    //最小权值累加
    visited[pos]=1;//标记该点

    for(j=1;j<=n;j++)   //更新权值
        if(visited[j]==0&&low[j]>map[pos][j])
            low[j]=map[pos][j];
    }
    return result;
}

int main()
{
    int i,v,j,ans;
    while(scanf("%d",&n)!=EOF)
    {
        memset(map,MaxInt,sizeof(map)); //所有权值初始化为最大
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
            {
                scanf("%d",&v);
                map[i][j]=map[i][j]=v;
            }
            ans=prim();
            printf("%d\n",ans);
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值