基础好不扎实啊,这样一个分层图都没有想出。
题目就不再写一遍了。
开始看到 \(n \le 50, x \le 50\) 的时候就已经想到可能是分层图了,可是觉得这个不太好分啊,也不知道应该分成什么样子。然后就想了一些奇奇怪怪的做法,还没想出来。
其实就是分层图。
既然这个钱在哪里补不好弄,那么就直接给它记录到状态里去,别看着\(10^9\) 那么大的数据范围,其实多余所有路径所需的钱的和就是无意义的了,因为你已经可以走到任何地方,都不需要再打工赚钱了,这样就可以用分层图了。
在实现的时候可以把连边加上两个权值,然后图还是原来那张图,只是状态里多记录一个,然后自己加就变成一条边连向自己,并且设置成相应的权值。
这样写起来比直接连所有边或者是啥边不连直接判要方便。
代码
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define int long long
const int N = 55, M = N*N*2, INF = 0x3f3f3f3f3f3f3f3fll;
int n, m, s, cost[M], len[M], next[M], head[N], vet[M], dis[N][M], num, LIM;
void add(int u, int v, int c, int w) {
vet[++num] = v, cost[num] = c, len[num] = w;
next[num] = head[u];
head[u] = num;
}
struct twt {
int u, c, d;
twt(int a = 0, int b = 0, int e = 0) { u = a, c = b, d = e; }
bool operator < (twt b) const {
if (d == b.d) return c > b.c;
return d > b.d;
}
};
void Dijkstra() {
memset(dis, 0x3f, sizeof dis);
std::priority_queue<twt> q;
dis[1][s] = 0;
q.push(twt(1, s, 0));
while (!q.empty()) {
twt now = q.top(); q.pop();
int u = now.u, c = now.c, d = now.d;
if (dis[u][c] != d) continue;
for (int i = head[u]; i; i = next[i]) {
int v = vet[i], l = len[i], t = c - cost[i];
if (v == u && c >= LIM) continue;
t = std::min(t, LIM);
if (t < 0) continue;
if (dis[v][t] > d + l) {
dis[v][t] = d + l;
q.push(twt(v, t, dis[v][t]));
}
}
}
}
signed main() {
std::cin >> n >> m >> s;
for (int i = 1, u, v, w, c; i <= m; i++) {
std::cin >> u >> v >> w >> c;
LIM += w;
add(u, v, w, c), add(v, u, w, c);
}
s = std::min(s, LIM);
for (int i = 1, c, d; i <= n; i++)
std::cin >> c >> d, add(i, i, -c, d);
Dijkstra();
for (int i = 2; i <= n; i++) {
int an = INF;
for (int j = 0; j < LIM; j++) an = std::min(an, dis[i][j]);
std::cout << an << '\n';
}
}
给代码块和折叠块换了个现代化一些的样式!_