【PAT】1030 Travel Plan——单源最短路径Dijkstra算法(第二标尺)打印路径两种写法

该博客分别展示了两种Dijkstra算法的实现:一种是基本的Dijkstra算法,用于求解最短路径;另一种结合了DFS,同时寻找最短路径和最小花费。这两种方法都在给定的图中找到从源点到目标点的最短路径,并输出路径及路径成本。
摘要由CSDN通过智能技术生成

//第一种:普通Dijkstra写法
#include <iostream>
#include <vector>
#define MAXN 510
#define MAXDATA 510
using namespace std;

int N,M,S,D;
//G:两点之间直接距离,C:两点之间直接花费
int G[MAXN][MAXN];int C[MAXN][MAXN];
int dist[MAXN];int cost[MAXN];
//dist[i]:i到源点距离,G[S][i]:i是否S邻接点
//cost[i]:i到源点花费,C[S][i]:i到S直接花费

int collected[MAXN];
int pre[MAXN];
int FindMin(){
    int minValue=MAXDATA,minId=-1;
    for(int i=0;i<N;i++){
        if(collected[i]==0 && dist[i]<minValue){
            minValue=dist[i];
            minId=i;
        }
    }
    return minId;
}

void Dijkstra(){
    fill(dist,dist+N,MAXDATA);
    fill(cost,cost+N,MAXDATA);
    fill(pre,pre+N,-1);
    dist[S]=0;
    cost[S]=0;
    while(1){
        int minId=FindMin();
        if(minId==-1) break;
        else{
            collected[minId]=1;
            for(int i=0;i<N;i++){
                if(collected[i]==0 && G[minId][i]!=MAXDATA){
                    if(dist[i]>dist[minId]+G[minId][i]){
                        dist[i]=dist[minId]+G[minId][i];
                        cost[i]=cost[minId]+C[minId][i];
                        pre[i]=minId;
                    }else if(dist[i]==dist[minId]+G[minId][i]){
                        if(cost[i]>cost[minId]+C[minId][i]){
                            cost[i]=cost[minId]+C[minId][i];
                            pre[i]=minId;
                        }
                    }
                }
            }
        }
    }
}

void PrintPath(){
    vector<int> path;
    int cur=D;
    while(cur!=-1){
       path.push_back(cur);
       cur=pre[cur];
    }

    for(int i=path.size()-1;i>=0;i--){
        printf("%d ",path[i]);
    }
}

int main(){
    scanf("%d %d %d %d",&N,&M,&S,&D);
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            G[i][j]=MAXDATA;
            C[i][j]=MAXDATA;
        }
    }

    int c1,c2,d,cos;
    for(int i=0;i<M;i++){
        scanf("%d %d %d %d",&c1,&c2,&d,&cos);
        G[c1][c2]=d;G[c2][c1]=d;
        C[c1][c2]=cos;C[c2][c1]=cos;
    }

    Dijkstra();
    PrintPath();
    printf("%d %d",dist[D],cost[D]);
   
    return 0;
}
//第二种:Dijkstra + DFS写法
#include <iostream>
#include <vector>
#define MAXN 510
#define MAXDATA 1000000000
using namespace std;

int N,M,S,D;
//G:两点之间直接距离,C:两点之间直接花费
int G[MAXN][MAXN];int C[MAXN][MAXN];
int dist[MAXN];
//dist[i]:i到源点距离,G[S][i]:i是否S邻接点
int collected[MAXN];
vector<int> pre[MAXN];
int FindMin(){
    int minValue=MAXDATA,minId=-1;
    for(int i=0;i<N;i++){
        if(collected[i]==0 && dist[i]<minValue){
            minValue=dist[i];
            minId=i;
        }
    }
    return minId;
}

void Dijkstra(){
    fill(dist,dist+N,MAXDATA);
    dist[S]=0;
    while(1){
        int minId=FindMin();
        if(minId==-1) break;
        else{
            collected[minId]=1;
            for(int i=0;i<N;i++){
                if(collected[i]==0 && G[minId][i]!=MAXDATA){
                    if(dist[i]>dist[minId]+G[minId][i]){
                        dist[i]=dist[minId]+G[minId][i];
                        pre[i].clear();
                        pre[i].push_back(minId);
                    }else if(dist[i]==dist[minId]+G[minId][i]){
                        pre[i].push_back(minId);
                    }
                }
            }
        }
    }
}

vector<int> tempPath;
vector<int> Path;
int minCost=MAXDATA,tempCost;
void DFS(int v){
    if(v == S){//到达叶子结点(即起点),tempPath存储一条完整路径
        //1:push
        tempPath.push_back(v);
        //2:culculate current cost
        tempCost=0;
        for(int i=tempPath.size()-1;i>0;i--){
            tempCost+=(C[tempPath[i]][tempPath[i-1]]);//cost里存的未必是当前路径的花费
        }
        if(tempCost<minCost){
            minCost=tempCost;
            Path=tempPath;//vector重载了=,可以直接赋值
        }
        //3:pop
        tempPath.pop_back();
        return;//本条路径结束,递归返回
    }

    //1:push
    tempPath.push_back(v);
    //2:递归计算当前结点下的所有路径
    for(int i=0;i<pre[v].size();i++){
        DFS(pre[v][i]);
    }
    //3:pop
    tempPath.pop_back();
}

int main(){
    scanf("%d %d %d %d",&N,&M,&S,&D);
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            G[i][j]=MAXDATA;
            C[i][j]=MAXDATA;
        }
    }

    int c1,c2,d,cos;
    for(int i=0;i<M;i++){
        scanf("%d %d %d %d",&c1,&c2,&d,&cos);
        G[c1][c2]=d;G[c2][c1]=d;
        C[c1][c2]=cos;C[c2][c1]=cos;
    }

    Dijkstra();
    DFS(D);
    for(int i=Path.size()-1;i>=0;i--){
        printf("%d ",Path[i]);
    }
    printf("%d %d",dist[D],minCost);
   
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值