练习36,最短路问题【Dijkstra算法/链式前向星】

题目:洛谷P1339 [USACO09OCT]Heat Wave G

题目描述

有一个 n n n 个点 m m m 条边的无向图,请求出从 s s s t t t 的最短路长度。

输入格式

第一行四个正整数 n , m , s , t n,m,s,t n,m,s,t
接下来 m m m 行,每行三个正整数 u , v , w u,v,w u,v,w,表示一条连接 u , v u,v u,v,长为 w w w 的边。

输出格式

输出一行一个整数,表示答案。

样例输入

7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1

样例输出

7

提示

【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 2500 1\le n \le 2500 1n2500 1 ≤ m ≤ 6200 1\le m \le 6200 1m6200 1 ≤ w ≤ 1000 1\le w \le 1000 1w1000
【样例说明】
5 → 6 → 1 → 4 5 \to 6 \to 1 \to 4 5614 为最短路,长度为 3 + 1 + 3 = 7 3+1+3 = 7 3+1+3=7

普通版Dijkstra
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define NOTLE ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define T int TT;cin >> TT;while (TT--)
#define lint long long
#define pb push_back
#define eb emplace_back
int n,m,s,t;
int ne[20010],last[20010],to[20010],w[20010],cnt=0;
int b[20010]={0},vis,d[20010]; //b标记是否经过该点,d存路程
void add(int x,int y,int z){ //链式前向星存图
	to[++cnt]=y; //to存终点
	ne[cnt]=last[x]; //ne存该出发点上一条边
	last[x]=cnt; //last存该出发点最后一条边
	w[cnt]=z; //w存边权
}
int main(){
    NOTLE;
    cin >> n >> m >> s >> t;
    for(int i=1;i<=n;i++) d[i]=INF; //初始化将到达每个点的路程设为无穷大
    for(int i=1;i<=m;i++){
    		int u,v,x;
    		cin >> u >> v >> x;
    		add(u,v,x); //无向图正反都存一遍
    		add(v,u,x);
    }
    vis=s;
    d[s]=0;
    while(!b[vis]){ //dijkstra
    		b[vis]=1;
    		for(int i=last[vis];i;i=ne[i])
    			if(!b[to[i]] && d[to[i]]>d[vis]+w[i])
    				d[to[i]]=d[vis]+w[i];
    		
    		int minn=INF;
    		for(int i=1;i<=n;i++) //查找没有经过的距起点最近的点
    			if(minn>d[i] && !b[i]) minn=d[i],vis=i;
    }
    cout << d[t];
    return 0;
}

堆优化版Dijkstra
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define NOTLE ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define T int TT;cin >> TT;while (TT--)
#define lint long long
#define pb push_back
#define eb emplace_back
int n,m,s,t;
int ne[20010],last[20010],to[20010],w[20010],cnt=0;
int b[20010]={0},d[20010]; //b标记是否经过该点,d存路程
priority_queue<pair<int,int>> q; //优先队列,first存路径相反数,second存点
void add(int x,int y,int z){ //链式前向星存图
	to[++cnt]=y; //to存终点
	ne[cnt]=last[x]; //ne存该出发点上一条边
	last[x]=cnt; //last存该出发点最后一条边
	w[cnt]=z; //w存边权
}
int main(){
    NOTLE;
    cin >> n >> m >> s >> t;
    for(int i=1;i<=n;i++) d[i]=INF; //初始化将到达每个点的路程设为无穷大
    for(int i=1;i<=m;i++){
    		int u,v,x;
    		cin >> u >> v >> x;
    		add(u,v,x); //无向图正反都存一遍
    		add(v,u,x);
    }
    d[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty()){ //dijkstra堆优化
            int p=q.top().second;
            q.pop();
            if(b[p]) continue;
    		b[p]=1;
    		for(int i=last[p];i;i=ne[i])
    			if(!b[to[i]] && d[to[i]]>d[p]+w[i]){
    				d[to[i]]=d[p]+w[i];
                    q.push(make_pair(-d[to[i]],to[i]));
    			}
    }
    cout << d[t];
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ILECY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值