题目

小明现在要追讨一笔债务,已知有 n 座城市,每个城市都有编号,城市与城市之间存在道路相连(每条道路都是双向的),经过任意一条道路需要支付费用。
小明一开始位于编号为 1 的城市,欠债人位于编号为 n 的城市。
小明每次从一个城市到达另一个城市需要耗时 1 天,而欠债人每天都会挥霍一定的钱,等到第 k 天后(即第 k+1 天)他就会离开城 n 并再也找不到了。
小明必须要在他离开前抓到他(最开始为第 0 天),同时希望自己的行程花费和欠债人挥霍的钱的总和最小,请计算一下最小总和。

解题思路

使用 BFS 算法。

表示与编号为 的城市连接的城市。

表示从城市 到城市 这条道路中需要支付的费用。

表示第 天欠债人挥霍的钱。

表示第 天到达城市 时的最小花费。在 函数中,实时更新最小花费。当天数大于 时,就不再计算。

最后,遍历从 1 到 天的 ,取最小值。

C++代码

#include<iostream>
#include<vector>
#include<queue>
#include<map>
using namespace std;

const int inf = 0x3f3f3f3f;
vector<vector<int>> edges;
map<pair<int,int>, int> mp;
vector<int> a;
vector<vector<int>> cost;

void bfs(int start, int k){
    queue<int> que, que2, que3;
    que.push(start);
    int day = 1;
    while(!que.empty()){
        int x = que.front();
        que.pop();
        for(int i=0; i<edges[x].size(); ++i){
            int y = edges[x][i];
            int tmp = cost[day-1][x] + mp[make_pair(x,y)] + a[day];
            if(cost[day][y] > tmp){
                cost[day][y] = tmp;
                que2.push(y);
            }
        }
        if(que.empty()){
            ++day;
            que = que2;
            que2 = que3;
        }
        if(day>k)
            return;
    }
}

int main(){
    int n, m, k;
    cin >> n >> m >> k;
    if(n==1){
        cout << 0 << endl;
        return 0;
    }
    edges.resize(n+1);
    int u, v, w;
    for(int i=0; i<m; ++i){
        cin >> u >> v >> w;
        edges[u].push_back(v);
        edges[v].push_back(u);
        mp[make_pair(u,v)] = w;
        mp[make_pair(v,u)] = w;
    }
    a.resize(n+1);
    for(int i=1; i<=n; ++i)
        cin >> a[i];

    cost.resize(k+1, vector<int>(n+1, inf));
    cost[0][1] = 0;
    bfs(1,k);

    int ans = inf;
    for(int i=1; i<=k; ++i){
        ans = min(ans, cost[i][n]);
    }
    if(ans == inf)
        cout << -1 << endl;
    else
        cout << ans << endl;
    return 0;
}