算法与数据结构实验题 10.33 坐火车
实验任务
在某国,有 \(n\) 个城市,有 \(m\) 条铁路将这 \(n\) 座城市连通,第 \(i\) 条铁路连通城市 \(u_i\) 和 \(v_i\) ,乘坐该条铁路的时间为\(t_i\)。在乘坐铁路之前需要购买车票,在城市 \(i\) 购买车票的排队时间为 \(t_i\) ,现在小明想知道从城市 \(1\) 到城市 \(n\) 最少需要多久时间。
数据输入
第一行给出两个整数 \(n\) 和 \(m\) ,代表城市的个数和铁路的数量。
第二行给出 \(n\) 个整数,第 \(i\) 个数表示在城市 \(i\) 购买车票的排队时间。
接下来 \(m\) 行,每行给出三个整数,表示第条铁路连通城市 \(u_i\) 和 \(v_i\) ,花费的时间为 \(t_i\) 。
数据范围:\(1<=n<=3e5, n<=m<=5e5, 0<=t_i<=1e8, 0<=a_i<=1e8\)
数据输出
输出一行,包含一个整数,表示从城市 \(1\) 到城市 \(n\) 的最小时间
输入示例
3 3
1 2 3
1 2 1
2 3 1
1 3 2
输出示例
3
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inf=1e18;
int n,m,x,y,z,a[500010];
ll dis[500010],ans;
int cnt,head[500010];
struct node {
int v,t,next; // next[i]表示与第i条边同起点的上一条边的储存位置
}edge[1000010];
void add(int f,int t,int v) { // f=from, t=to, v=val
edge[cnt].t=t;
edge[cnt].v=v;
edge[cnt].next=head[f]; // head[i]表示以i为起点的最后一条边的储存位置
head[f]=cnt++;
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof head);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&x,&y,&z);
add(x,y,z+a[x]);
add(y,x,z+a[y]);
}
for(int i=2;i<=n;i++) dis[i]=inf;
queue<int>que;
que.push(1);
while(!que.empty()) {
int f=que.front(); que.pop();
for(int i=head[f];i!=-1;i=edge[i].next) {
int t=edge[i].t,v=edge[i].v;
if(dis[t]>dis[f]+v) {
dis[t]=dis[f]+v;
if(t==n) ans=dis[t];
else que.push(t);
}
}
}
printf("%lld",ans);
return 0;
}
思路
一个无向图的最短路考查,使用简单的SPFA进行实现,其中关于存边,我将购买车票的费用加入到每一条边的权值中,注意方向不同,存的车票费用也不同
参见:OI Wiki - 最短路 - SPFA
二改:由于忽略了数据范围导致寄了,注意要把dis数组开成long long,代码已更新
三改:DS卡我vector存图,现已加入链式前向星