1030 Travel Plan(30 分)

1030 Travel Plan(30 分)

题目大意

求起点到终点的最短路径最短距离和花费,要求首先路径最短,其次花费最少,要输出完整路径

基本思路

最直接的一道Dij+dfs题目,直接套用算法笔记给出的模板即可解决

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN=510;
const int INF=1000000000;

int n,m,s,e;
int G[MAXN][MAXN];//邻接矩阵存储这一张图。初始化每个元素为INF,再从题目中读入边的距离
int vis[MAXN];//表示某个顶点是否被访问。初始化所有顶点为未访问
int d[MAXN];//d[u]记录起点到顶点u的最短距离。初始化d[s]=0,其余的d[u]均为INF
vector<int> pre[MAXN];//pre[u]记录从起点到达顶点u的最短路径上的所有前驱节点。不需要初始化
int cost[MAXN][MAXN];//边权。初始化每个元素为INF,再从题目中读入新的边权
//第一标尺
void Dijkstra(){
    //初始化相关数据
    fill(d,d+MAXN,INF);
    d[s]=0;
    //将V中的所有顶点放入S
    for(int i=0;i<n;i++){
        //求出离起点最近的顶点编号u和距离MIN
        int u=-1,MIN=INF;
        for(int j=0;j<n;j++){
            if(vis[j]==false&&d[j]<MIN){
                u=j;
                MIN=d[j];
            }
        }
        if(u==-1) return;//已经没有顶点可以到达起点,直接返回
        else vis[u]=true;//标记u为已访问,把顶点u放入集合S
        //开放所有顶点u出发的边。看看有没有通过u使得某个未访问的顶点v的d[v]减小
        for(int v=0;v<n;v++){
            if(vis[v]==false&&G[u][v]!=INF){
                if(d[u]+G[u][v]<d[v]){
                    d[v]=d[u]+G[u][v];//优化d[v]
                    pre[v].clear();//清空pre[v]
                    pre[v].push_back(u);//令v的前驱为u
                }
                else if(d[u]+G[u][v]==d[v]){
                    pre[v].push_back(u);//令v的前驱为u
                }
            }
        }
    }
}
//第二标尺
int optcost=INF;//边权和的最小值(第二标尺的最优解)
vector<int> bestPath,tempPath;//最优的路径,临时的路径
void DFS(int end){
    if(end==s){
        tempPath.push_back(end);
        int tempcost=0;
        for(int i=tempPath.size()-1;i>0;i--){
            int u=tempPath[i],v=tempPath[i-1];
            tempcost=tempcost+cost[u][v];
        }
        if(tempcost<optcost){
            optcost=tempcost;
            bestPath=tempPath;
        }       
        tempPath.pop_back();
        return;
    }
    tempPath.push_back(end);//将当前访问的结点加入临时路径tempPath的最后面
    for(int i=0;i<pre[end].size();i++){//对结点end的每一个前驱节点进行递归
        DFS(pre[end][i]);
    }
    tempPath.pop_back();//遍历完所有的前驱结点,将当前的结点end删除
}
int main(){
    //读入数据并初始化相关的数据结构
    cin>>n>>m>>s>>e;
    fill(G[0],G[0]+MAXN*MAXN,INF);
    fill(cost[0],cost[0]+MAXN*MAXN,INF);
    for(int i=0;i<m;i++){
        int u,v,edgedis,edgeweight;
        cin>>u>>v>>edgedis>>edgeweight;
        G[u][v]=G[v][u]=edgedis;//无向图
        cost[u][v]=cost[v][u]=edgeweight;//无向图       
    }
    //对第一标尺进行Dijkstra算法
    Dijkstra();
    //对第二标尺进行操作
    int end=e;
    DFS(end);//从终点开始DFS(回溯法)遍历所有路径,选取第二标尺最优的那一条
    //输出最优的那条路径和最优的第二标尺
    for(int i=bestPath.size()-1;i>=0;i--){
        printf("%d ",bestPath[i]);
    }
    printf("%d %d\n",d[e],optcost);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值