1

题目要求:

现有N个城市,M条道路,并给出M条道路的距离和耗费,现在给定起点S和终点D,要求求出起点到终点最短路径、最短距离和耗费,若有多条输出耗费最小的

算法思路:

这个是单源最短距离问题,这里使用Dijkstra算法的进行求解,这里需要求解的信息主要有三个,而且存在两个不同优先级的约束条件,那么我们先使用Dijkstra算法求解获得具备最短距离的所有最短
路径,然后使用深度优先遍历所有的最短路径,在其他找出耗费最小的路径即为所求。

数据的存储:

这里使用c数组保存每一个城市到起点的最小耗费,cost数组保存任意两个城市之间的耗费 ,pre数组保存每个结点的前驱结点

Dijkstra算法求解

我们循环N次,每一次循环,首先从所有未访问的点中找到距离起点最小的点nearest,然后再优化借助nearest到其他未访问的点的最短距离,如果借助nearest到达当前点j更短,那么就更新到达j的最短距离,最小耗费和到达j的前驱节点。如果最短距离一样但是通过nearest到达j的耗费更小,那么就更新到达j的最小耗费和j的前驱节点。

DFS搜索:

我们从终点开始搜索,每次递归就访问该节点,知道遇到起点,到达递归边界,shortest保存当前搜索的最短路径,遍历当前路径上的每一条边,累加所有的边权获得总耗费,如果total_cost==c[D]说明当前的是最优的,使用result保存最优路径,最后得将入栈节点退栈并返回,递归体为访问每一个当前节点的前驱节点,访问完毕后也得退栈回溯。

注意点:

  • 1、计算耗费的时候只需计算n-1条边,并且在输出的时候得倒着访问。

提交结果:

image.png

AC代码:

#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

int N,M,S,D;// 顶点数,边数,起点和终点。 
int G[505][505];// 边权,其值表示为两点之间的距离
int cost[505][505];// 两点之间的耗费 
bool visited[505];// 访问标记数组
int dis[505];// 每一个城市到起点的距离
int c[505];//每一个城市到起点的最小耗费
vector<int> pre[505];// 保存每一个站点的前驱结点
vector<int> shortest;//最短路径
vector<int> result;// 最优路径

void DFS(int start){
    shortest.push_back(start);
    if(start==S){
        // 当前结点是终点 
        int total_cost = 0;
        for(int i=shortest.size()-1;i>0;--i){
            total_cost += cost[shortest[i]][shortest[i-1]];
        }
        if(total_cost==c[D]){
            // 当前的路径是最优的
            result = shortest;
        }
        shortest.pop_back();
        return;
    }
    for(int i=0;i<pre[start].size();++i){
        DFS(pre[start][i]);
    }
    shortest.pop_back();
} 

void Dijkstra(int start){
    // 初始化 
    fill(dis,dis+505,0x3fffffff);
    dis[start] = 0;
    c[start] = 0;
    // 循环N次
    for(int i=0;i<N;++i){
        // 首先从所有未访问的点中找到距离起点最小的点 
        int nearest,minDis=0x3fffffff;
        for(int j=0;j<N;++j){
            if(!visited[j]&&minDis>dis[j]){
                nearest = j;
                minDis = dis[j];
            }
        }
        if(minDis==0x3fffffff) return ;// 没有找到,说明其他点不再连通 
        // 优化借助nearest到其他未访问的点的距离
        visited[nearest] = true;
        for(int j=0;j<N;++j){
            if(!visited[j]&&G[nearest][j]!=0){
                if(dis[j]>dis[nearest]+G[nearest][j]){
                    dis[j] = dis[nearest]+G[nearest][j];
                    c[j] = c[nearest] + cost[nearest][j];
                    pre[j].clear();
                    pre[j].push_back(nearest);
                }else if(dis[j]==dis[nearest]+G[nearest][j]&&c[j]>c[nearest]+cost[nearest][j]){
                    c[j] = c[nearest] + cost[nearest][j];
                    pre[j].push_back(nearest);
                }
            }
        }
    } 
} 

int main(){
    scanf("%d %d %d %d",&N,&M,&S,&D);
    int a,b,distance,C;
    for(int i=0;i<M;++i){
        scanf("%d %d %d %d",&a,&b,&distance,&C);
        G[b][a] = G[a][b] = distance;
        cost[b][a] = cost[a][b] = C;
    }
    Dijkstra(S);
    DFS(D);
    for(int i=result.size()-1;i>=0;--i){
        printf("%d ",result[i]);
    }
    printf("%d %d",dis[D],c[D]);
    return 0;
}

乔梓鑫
569 声望16 粉丝

主要分享个人学习经验和心得