C++最短路径(迪杰斯特拉算法)

前言

Dijkstra算法能够有效地计算出源点到其余所有顶点的最短路径。

该算法在运行过程中将顶点集合V分成两个集合S和T。

(1)S:已确定的顶点集合,初始只含源点s。

(2)T=V-S:尚未确定的顶点集合。

算法反复从T中选择当前到源点s最近的顶点u,将u加入集合S,然后对所有从u发出的边进行松弛操作。

 

【题目1:畅通工程续】

现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

 

【输入】

第一行:N(0<N<200),M(0<M<1000),分别代表城镇数和已修道路数。

接下来M行,A,B,X,表示A—B(X)的双向道路。

再接下来的下一行:S(起点),T(终点)。

 

【输出】

输出最短需要行走的距离。若不存在则输出-1;

 

【样例输入】

3 3  
0 1 1  
0 2 3
1 2 1
0 2 
3 1 
0 1 1
1 2

【样例输出】

2 
-1

【代码】

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<climits>
using namespace std;
const int MAXN=200;
const int INF=INT_MAX;//无穷大设为很大的数
struct Edge{
    int to;//终点
    int length;
    Edge(int t,int l){
        to=t;
        length=l;
    }
};
struct Point{
    int number;
    int distance;
    Point(int n,int d)
    {
        number=n;
        distance=d;
    }
    bool operator<(const Point&p)const{
        return distance>p.distance;//距离小的优先级高
    }
};
vector<Edge> graph[MAXN];//邻接表实现的图
int dis[MAXN];//源点到各点距离

void Dijkstra(int s){
    priority_queue<Point> myPriorityQueue;
    dis[s]=0;
    myPriorityQueue.push(Point(s,dis[s]));
    while(!myPriorityQueue.empty()){
        int u=myPriorityQueue.top().number;//离源点最近的点
        myPriorityQueue.pop();
        for(int i=0;i<graph[u].size();i++)
        {
            int v=graph[u][i].to;
            int d=graph[u][i].length;
            if(dis[v]>dis[u]+d){
                dis[v]=dis[u]+d;
                myPriorityQueue.push(Point(v,dis[v]));
            }
        }
    }
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        memset(graph,0,sizeof(graph));//图初始化
        fill(dis,dis+n,INF);//距离初始化为无穷
        while(m--)
        {
            int from,to,length;
            cin>>from>>to>>length;
            graph[from].push_back(Edge(to,length));
            graph[to].push_back(Edge(from,length));
        }
        int s,t;
        cin>>s>>t;
        Dijkstra(s);
        if(dis[t]==INF)
            dis[t]=-1;
        cout<<dis[t]<<endl;
    }
    return 0;
}

 

题目2:最短路径问题

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

 

输入描述:

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

输出描述:

输出 一行有两个数, 最短距离及其花费。

示例1

输入

3 2
1 2 5 6
2 3 4 5
1 3
0 0

输出

9 11

注意

本题不仅需要求起点到终点的最短距离,还需要在有多条最短路径时,选取花费最少的那一条,只需更改Dijstra算法中的松弛操作:新的路径若在距离上优于之前的路径,或者新的路径在距离上等于之前的路径,但花费要优于之前的路径,则更新路径和花费。

代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<climits>

using namespace std;
const int MAXN=1001;
const int INF=INT_MAX;
struct Edge{
    int to;
    int length;
    int price;
    Edge(int t,int l,int p)
    {
        to=t;
        length=l;
        price=p;
    }
};
struct Point{
    int number;
    int distance;
    Point(int n,int d)
    {
        number=n;
        distance=d;
    }
    bool operator<(const Point& p)const{
        return distance>p.distance;//距离小的优先级高
    }
};
vector<Edge> graph[MAXN];
int dis[MAXN];
int cost[MAXN];
void Dijkstra(int s)
{
    priority_queue<Point> myPriorityQueue;
    dis[s]=0;
    cost[s]=0;
    myPriorityQueue.push(Point(s,dis[s]));
    while(!myPriorityQueue.empty())
    {
        int u=myPriorityQueue.top().number;
        myPriorityQueue.pop();
        for(int i=0;i<graph[u].size();i++)
        {
            int v=graph[u][i].to;
            int l=graph[u][i].length;
            int p=graph[u][i].price;
            if((dis[v]==dis[u]+l && cost[v]>cost[u]+p)||dis[v]>dis[u]+l)
            {
                dis[v]=dis[u]+l;
                cost[v]=cost[u]+p;
                myPriorityQueue.push(Point(v,dis[v]));
            }
        }
    }
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0&&m==0)
            break;
        memset(graph,0,sizeof(graph));
        fill(dis,dis+n+1,INF);
        fill(cost,cost+1,INF);
        while(m--)
        {
            int from,to,length,price;
            cin>>from>>to>>length>>price;
            graph[from].push_back(Edge(to,length,price));
            graph[to].push_back(Edge(from,length,price));
        }
        int s,t;
        cin>>s>>t;
        Dijkstra(s);
        cout<<dis[t]<<" "<<cost[t]<<endl;
    }
    return 0;
}

 

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值