其他分享
首页 > 其他分享> > 题解 [ABC164E] Two Currencies

题解 [ABC164E] Two Currencies

作者:互联网

基础好不扎实啊,这样一个分层图都没有想出。

题目就不再写一遍了。

开始看到 \(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';
    }
}

给代码块和折叠块换了个现代化一些的样式!_

标签:Currencies,num,int,题解,add,ABC164E,twt,LIM,dis
来源: https://www.cnblogs.com/Acfboy/p/ABC164E.html