最短路径

来源:互联网 发布:剑三温柔花哥捏脸数据 编辑:程序博客网 时间:2024/06/15 04:40

最短路径


Dijkstra算法模版,如果不需要输出步骤,只需删除searchPath()函数即可

不适合于有负圈的计算

可以使用priority_queue的优先队列进行排序方便查找,节省时间

#include <iostream>

#include <fstream>

#include <stdio.h>

using namespacestd;

const int maxnum =100;

const int maxint =999999;

int i,j;

void Dijkstra(int n,int v,int *dist,int *prev,int c[maxnum][maxnum])

{

    bool s[maxnum];   //判断是否已存入该点到S集合中

    for(int i=1; i<=n; i++)

    {

        dist[i] = c[v][i];

        s[i] = 0;    //初始都未用过该点

        if(dist[i] ==maxint)

            prev[i] = 0;

        else

            prev[i] = v;

    }

    dist[v] = 0;

    s[v] = 1;

    

    // 依次将未放入S集合的结点中,取dist[]最小值的结点,放入结合S

    // 一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度

    for(i=2;i<=n;i++)

    {

        int tmp =maxint;

        int u = v;

        // 找出当前未使用的点jdist[j]最小值

        for(int j=1; j<=n; j++)

            if((!s[j]) && dist[j]<tmp)

            {

                u = j;              // u保存当前邻接点中距离最小的点的号码

                tmp = dist[j];

            }

        s[u] = 1;   //表示u点已存入S集合中

        

        // 更新dist

        for(j=1;j<=n;j++)

            if((!s[j]) && c[u][j]<maxint)

            {

                int newdist = dist[u] + c[u][j];

                if(newdist < dist[j])

                {

                    dist[j] = newdist;

                    prev[j] = u;

                }

            }

    }

}

void searchPath(int *prev,int v,int u)

{

    int que[maxnum];

    int tot =1;

    que[tot] = u;

    tot++;

    int tmp = prev[u];

    while(tmp != v)

    {

        que[tot] = tmp;

        tot++;

        tmp = prev[tmp];

    }

    que[tot] = v;

    for(int i=tot; i>=1; i--)

        if(i !=1)

            cout << que[i] <<" -> ";

        else

            cout << que[i] <<endl;

}


int main()

{

    //freopen("input.txt", "r", stdin);

    // 各数组都从下标1开始

    int dist[maxnum];    //表示当前点到源点的最短路径长度

    int prev[maxnum];    //记录当前点的前一个结点

    int c[maxnum][maxnum];  //记录图的两点间路径长度

    int n, line;            //图的结点数和路径数

    

    // 输入结点数

    cin >> n;

    // 输入路径数

    cin >> line;

    int p, q, len;         //输入p, q两点及其路径长度

    // 初始化c[][]maxint

    for(int i=1; i<=n; i++)

        for(int j=1; j<=n; j++)

            c[i][j] = maxint;

    for(i=1;i<=line;i++)

    {

        cin >> p >> q >> len;

        if(len < c[p][q])      //有重边

        {

            c[p][q] = len;      // p指向q

            c[q][p] = len;      // q指向p,这样表示无向图

        }

    }

    for(i=1;i<=n;i++)

        dist[i] =maxint;

    Dijkstra(n,1, dist, prev, c);

    // 最短路径长度

    cout <<"源点到最后一个顶点的最短路径长度: " << dist[n] <<endl;

    // 路径

    cout <<"源点到最后一个顶点的路径为: ";

    searchPath(prev,1, n);

    return0;

}


测试数据:

输入:

5

7

1 2 10

1 4 30

1 5 100

2 3 50

3 510

4 320

4 560

输出:

源点到最后一个顶点的最短路径长度: 60
源点到最后一个顶点的路径为: 1 -> 4 -> 3 -> 5




Bellman-Ford  算法,可判断是否存在负圈

代码可计算有向图,输出到每个点的最短路径


#include<iostream>

#include<cstdio>

using namespacestd;


#define MAX 0x3f3f3f3f

#define N 1010

int nodenum, edgenum, original;//点,边,起点


typedef struct Edge//

{

    int u, v;

    int cost;

}Edge;


Edge edge[N];

int dis[N], pre[N];


bool Bellman_Ford()

{

    for(int i =1; i <=nodenum; ++i)//初始化

        dis[i] = (i ==original ?0 :MAX);

    for(int i =1; i <=nodenum -1; ++i)

        for(int j =1; j <=edgenum; ++j)

            if(dis[edge[j].v] > dis[edge[j].u] +edge[j].cost)//松弛(顺序一定不能反~

            {

                dis[edge[j].v] =dis[edge[j].u] +edge[j].cost;

                pre[edge[j].v] =edge[j].u;

            }

    bool flag =1;//判断是否含有负权回路

    for(int i =1; i <=edgenum; ++i)

        if(dis[edge[i].v] > dis[edge[i].u] +edge[i].cost)

        {

            flag = 0;

            break;

        }

    return flag;

}


void print_path(int root)//打印最短路的路径(反向)

{

    while(root !=pre[root])//前驱

    {

        printf("%d-->", root);

        root = pre[root];

    }

    if(root ==pre[root])

        printf("%d\n", root);

}


int main()

{

    scanf("%d%d%d", &nodenum, &edgenum, &original);

    pre[original] =original;

    for(int i =1; i <=edgenum; ++i)

    {

        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);

    }

    if(Bellman_Ford())

        for(int i =1; i <=nodenum; ++i)//每个点最短路

        {

            printf("%d\n",dis[i]);

            printf("Path:");

            print_path(i);

        }

    else

        printf("have negative circle\n");

    return0;

}


测试数据:

输入:

4 6 1 

1 2 2

1 3 5 

4 1 10

2 4 4 

4 2 4

3 4 2

输出:

0

Path:1

2

Path:2-->1

5

Path:3-->1

6

Path:4-->2-->1



输入:

4 6 1

1 2 20

1 3 5

4 1 200

2 4 4 

4 2 4

3 4 2

输出:

have negative circle


0 0