松弛操作,循环dp

题意:

图片说明

分析:

又是这种题,很好,对于已经明白松弛操作与循环dp的我来说已经不成问题了。
给出dp状态dp[i][j] 指在第j步到达节点i的最短路径
d[i][j] = min(d[k][j-1] + edge(i,k) + cost[j] k为i相邻节点)
这是个无限递归的循环dp
关于循环dp https://blog.nowcoder.net/n/8316b13c345d49b08b2ae7f41c49da71
##代码如下:

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<functional>
using namespace std;
typedef pair<int, int> pii;
typedef pair<int, pii> pip;
struct edge { int to, cost; };
const int max_n = 1e3 + 100;
const int inf = 2e9;
int d[max_n][15];
vector<edge> G[max_n];
int n, m, k;
int cost[15];


void dijstra(int s,int t) {
    for (int i = 1;i <= n;i++)
        for (int j = 0;j <= k;j++)
            d[i][j] = inf;
    priority_queue<pip, vector<pip>, greater<pip>> que;
    d[s][t] = 0;que.push({ d[s][t],{s,t} });
    while (!que.empty()) {
        pip p = que.top();que.pop();
        pii pos = p.second;int dist = p.first;
        if (dist > d[pos.first][pos.second])continue;
        d[pos.first][pos.second] = dist;
        if (pos.second == k)continue;
        for (int i = 0;i < G[pos.first].size();i++) {
            edge& e = G[pos.first][i];
            if (d[e.to][pos.second + 1] < dist + e.cost + cost[pos.second + 1])continue;
            d[e.to][pos.second + 1] = dist + e.cost + cost[pos.second + 1];
            que.push({ d[e.to][pos.second + 1],{e.to,pos.second + 1} });
        }
    }
}


int main() {
    ios::sync_with_stdio(0);
    cin >> n >> m >> k;
    for (int i = 1;i <= m;i++) {
        int u, v, w;cin >> u >> v >> w;
        G[u].push_back({ v,w });
        G[v].push_back({ u,w });
    }
    for (int i = 1;i <= k;i++)cin >> cost[i];
    dijstra(1, 0);
    int ans = inf;
    for (int i = 0;i <= k;i++)
        ans = min(d[n][i], ans);
    if (ans == inf)cout << -1 << endl;
    else cout << ans << endl;
}