HDU 3790. 最短路径问题

问题描述:
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入:
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。(1

输出:
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。(1

样例输入:
3 2
1 2 5 6
2 3 4 5
1 3
0 0

样例输出:
9 11

最近想练练DijkStra,在LeetCode上愣是没找到相关的题,于是跑到HDU上选了这么一道题。
该题要求我们在保证最短路径的基础上花费越小越好,所以我们不仅要在距离更短时更新距离和花费,在距离相等时也要选择更少的花费。
该题没有要求我们输出最短路径,实在遗憾,这里使用了一个前驱数组pre记录了各点的前驱,根据pre逆序查找即可得到最短路径。
同一套算法,一开始我使用Java代码编写提交后被判定超时(超出2000ms),改用C++实现只需要312ms完美AC,看来还是C++比较适合在OJ上刷题。当然,Java在LeetCode上还是很好用的。
C++源码如下:

#include
#include
using namespace std;

int n;                  // n个点,点的编号从1开始
int m;                  // m条边
const int MAXN = 1000 + 10;
int topo[MAXN][MAXN];   // 邻接矩阵,值为距离
int cost[MAXN][MAXN];   // 花费
int start;
int end;

void dijkstra(int start, int end)
{
    int dist[MAXN];         // 起点到该点的最短路径长度
    int pathCost[MAXN];     // 起点到该点的最短路径花费
    bool S[MAXN];         // 已求得最短路径的顶点集
    int pre[MAXN];        // 最短路径上该点的前驱,用来记录最短路径
    for (int i = 1; i <= n; i++)
    {
        dist[i] = topo[start][i];   // 初始时为起点到该点的长度
        if (dist[i] < numeric_limits::max())
            pre[i] = start;     
        pathCost[i] = cost[start][i];
        S[i] = false;               // 不要忘了给bool型初始化,不然有可能是ture
    }
    S[start] = true;                // 初始时S中只有起点

    for (int i = 1; i < n; i++)
    {
        int minDist = numeric_limits::max();
        int u = 0;
        for (int j = 1; j <= n; j++)
        {
            if (!S[j] && dist[j] < minDist)
            {
                minDist = dist[j];
                u = j;  // 到该点已是最短路径,将作为中间结点进行松弛操作
            }
        }
        S[u] = true;    // 加入到S中
        for (int j = 1; j <= n; j++)
        {
            if (!S[j] && topo[u][j] < numeric_limits::max())   // 对所有从结点u发出的边(u, j)进行松弛操作
            {
                if (dist[u] + topo[u][j] < dist[j])
                {
                    dist[j] = dist[u] + topo[u][j];
                    pathCost[j] = pathCost[u] + cost[u][j];
                    pre[j] = u;     // 更新前驱结点
                }
                else if (dist[u] + topo[u][j] == dist[j] && pathCost[u] + cost[u][j] < pathCost[j])
                {
                    pathCost[j] = pathCost[u] + cost[u][j];
                }
            }
        }
    }
    printf("%d %d\n", dist[end], pathCost[end]);
}

int main()
{
    int a, b, d, p;
    int start, end;
    while (scanf("%d%d", &n, &m), n || m)
    {
        for (int i = 1; i <= n; i++)        // 初始化邻接矩阵
        {
            for (int j = 1; j <= n; j++)
            {
                if (i == j)
                    topo[i][j] = 0;
                else
                    topo[i][j] = numeric_limits::max();
            }
        }
        for (int i = 0; i < m; i++)         // 构造邻接矩阵
        {
            scanf("%d%d%d%d", &a, &b, &d, &p);
            if (d < topo[a][b])                         // 取距离最小的边
            {
                topo[a][b] = topo[b][a] = d;
                cost[a][b] = cost[b][a] = p;
            }
            else if (d == topo[a][b] && p < cost[a][b]) // 距离相同,取花费最小的边
            {
                cost[a][b] = cost[b][a] = p;
            }
        }
        scanf("%d%d", &start, &end);
        dijkstra(start, end);
    }
    return 0;
}

显然,DijkStra算法的时间复杂度为O(n^2)

你可能感兴趣的:(HDU 3790. 最短路径问题)