建立分层图,即复制 $k + 1$ 张图,层与层之间建立零权边。对源点进行 $dijstra$ ,得出源点到分层图上任意一点的最短路。由于最优方案并非要把所有次数用完,所以最后需要取终点的所有可能的最小值。需要注意空间大小,如果数据过大无法使用。
该题为模板题,无特殊。
#include<iostream> #include<cstring> #include<queue> #define maxn 50050 using namespace std; struct edge { int to, val, nxt; }g[maxn*44]; struct node { int s, w; bool operator<(const node& a)const { if (w != a.w)return w > a.w; else return s < a.s; } }; priority_queue<node> q; int cnt, hd[maxn*11], dis[maxn * 11], u, v, w, n, m, s, t, k, ans = INT32_MAX; bool vis[maxn * 11]; void add(int u, int v, int w) { g[++cnt].val = w; g[cnt].to = v; g[cnt].nxt = hd[u]; hd[u] = cnt; } int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m >> k >> s >> t; for (int i = 1; i <= m; i++) { cin >> u >> v >> w; add(u, v, w); add(v, u, w); for (int j = 1; j <= k; j++) { add(u + j * n, v + j * n, w); add(v + j * n, u + j * n, w); add(u + j * n - n, v + j * n, 0); add(v + j * n - n, u + j * n, 0); } } memset(dis, 63, sizeof(dis)); dis[s] = 0; q.push({ s,0 }); while (!q.empty()) { int u = q.top().s; q.pop(); if (vis[u])continue; vis[u] = true; for (int i = hd[u]; i; i = g[i].nxt) if (dis[g[i].to] > dis[u] + g[i].val && !vis[g[i].to]) { dis[g[i].to] = dis[u] + g[i].val; q.push({ g[i].to,dis[g[i].to] }); } } for (int i = 0; i <= k; i++) ans = min(ans, dis[t + i * n]); cout << ans; return 0; }
DP思想,定义状态 $f(i,j)$ 为到达点 $i$ ,花费 $j$ 次机会的最短路径。在优先队列中多加入一个 $cost$ 的变量来限制使用机会的次数。在松弛操作中比朴素的 $dijstra$ 要多一个使用一次机会的情况。对空间的要求比分层图小得多,可以优先考虑。
该题为 $dijstra$ 的变种,最短路径是整条路径的最大权值,在松弛时需要拿当前路径和两点间权值的最大值来操作。
#include<iostream> #include<queue> #include<cstring> #define maxn 1007 using namespace std; struct edge { int to, val, nxt; }g[maxn*20]; struct node { int s, c; long long w; bool operator <(const node& a)const { return w > a.w; } }; int hd[maxn], cnt, n, m, k, u, v, w; bool vis[maxn][maxn]; long long dis[maxn][maxn]; priority_queue<node> q; void add(int u, int v, int w) { g[++cnt].val = w; g[cnt].to = v; g[cnt].nxt = hd[u]; hd[u] = cnt; } int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m >> k; for (int i = 1; i <= m; i++) { cin >> u >> v >> w; add(u, v, w); add(v, u, w); } memset(dis, 64, sizeof(dis)); dis[1][0] = 0; q.push({ 1,0,0 }); long long ans = dis[0][0]; while (!q.empty()) { int u = q.top().s, cost = q.top().c; q.pop(); if (vis[u][cost])continue; vis[u][cost] = true; for (int i = hd[u]; i; i = g[i].nxt) { int v = g[i].to; if (dis[v][cost] > max((long long)g[i].val,dis[u][cost]) && !vis[v][cost]) { dis[v][cost] = max((long long)g[i].val,dis[u][cost]); q.push({ v, cost, dis[v][cost] }); } if (dis[v][cost + 1] > dis[u][cost] && cost < k && !vis[v][cost + 1]) { dis[v][cost + 1] = dis[u][cost]; q.push({ v,cost + 1,dis[v][cost + 1] }); } } } for (int i = 0; i <= k; i++) ans = min(ans, dis[n][i]); if (ans == dis[0][0])cout << -1; else cout << ans; return 0; }