首先根据题目描述,我们可以得知我们需要寻找到起点到终点的最短时长(最短路径问题),而要找出最短路径问题,我们可以用迪杰克拉算法,就是从起始点开始遍历,用优先队列优先从最短路径的点开始遍历,如果花费时间存在更小方案就更新dist数组,最后直接输出dist[n] - time[n]即可
上代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#include<vector>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
struct Node{
int value;
vector <Node*> children;//存储子节点
int time;//存储时间
vector <int> length;//存储路径权值
};
int n, m;
unordered_map <int, Node*> mp;
const int N = 1e3 + 10;
int dist[N];
bool st[N] = {0};//存储每个点的访问情况,如果已经有最短路径了,就标志为1
void djkl()
{
//参数分别是当前节点到目标点的最短距离,以及目标点,第二个参数是用vector作为底层容器,第三个是按照从小到大依次排列,如果要从大到小就用less<PII>
priority_queue<PII, vector<PII>, greater<PII>> q;
memset(dist, 0x3f3f3f3f, sizeof(dist));//初始化dist数组为最大值
dist[1] = 0;//起始点到起始点的距离是0
q.push({0, 1});//初始化优先队列,先将起点放进来,第一个参数0表示路径长度为0,1表示目标点
while(!q.empty()){
auto t = q.top(); q.pop();//取出当前信息
if(st[t.second]) continue;//如果当前点是最优的点,就继续向下访问
st[t.second] = true;//否则就标记当前点
for(int i = 0; i < mp[t.second]->children.size(); i++){//从当前点开始访问其他可通路径
int num = mp[t.second]->children[i]->value;//取出下一个点的编号
//如果到当前点所花费的时间大于到上一个点花费的最短时间和隔离时间还有路径时间的总和,就进行更新
if(dist[num] > dist[t.second] + mp[t.second]->length[i] + mp[num]->time){
dist[num] = dist[t.second] + mp[t.second]->length[i] + mp[num]->time;
q.push({dist[num], num});//更新队列
} //因为起始点不用隔离,因此直接用子节点的隔离时间
}
}
cout << dist[n] - mp[n]->time << endl;//因为到达第n个城市不需要隔离,因此需要减去当前隔离时间
return;
}
int main(void)
{
cin >> n >> m;
Node node[n + 10];
for(int i = 1; i <= n; i++){
node[i].value = i;
mp[i] = &node[i];
int time1; cin >> time1;
mp[i]->time = time1;
}
for(int i = 1; i <= m; i++){
int x, y, z;
cin >> x >> y >> z;
mp[x]->children.push_back(mp[y]);
mp[y]->children.push_back(mp[x]);
mp[x]->length.push_back(z);
mp[y]->length.push_back(z);
}
djkl();
return 0;
}