https://ac.nowcoder.com/acm/contest/329/B

题解:

std

作者:儒生雄才1
链接:https://ac.nowcoder.com/discuss/152781
来源:牛客网
 

有向无环图(DAG)上的最短路。
注意:负权值边的存在使得 Dijkstra 算法不适用,特殊 DAG 的性质使得 SPFA 算法无法在规定的时间限内求解出答案。 考虑到 DAG 的特殊性,按照原图节点的拓扑顺序依次递推距离即可求解。

令𝑑𝑖表示节点1到i的最短路,𝑝𝑟𝑒𝑣_𝑖表示节点的先驱集合。则有:

di=min(dj+cost(j,i))其中𝑗∈𝑝𝑟𝑒𝑣_𝑖,其中𝑐𝑜𝑠𝑡(𝑗,𝑖)表示从节点j到节点i的有向边的边权。

按照节点拓扑顺序计算d即可。

时间复杂度:𝑂(𝑁+𝑀)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
struct Topo
{
    int n;
    int deg[MAXN];
    LL dist[MAXN];
    struct Edge
    {
        int to, value;
        Edge(int to, int value) : to(to), value(value) {}
    };
    vector<Edge> edges[MAXN];
    void init(int n)
    {
        this->n = n;
        memset(deg, 0, sizeof deg);
        for (int i = 1; i <= n; i ++)
            edges[i].clear();
    }
    void add_edge(int from, int to, int value)
    {
        edges[from].emplace_back(to, value);
        deg[to]++;
    }
    LL solve(int s, int t)
    {
        memset(dist, 0x3f, sizeof dist);
        dist[s] = 0;
        queue<int> q;
        for (int i = 1; i <= n; i ++)
            if (deg[i] == 0) q.push(i);
        while (!q.empty())
        {
            int x = q.front();
            for (auto& i : edges[x])
            {
                dist[i.to] = min(dist[i.to], dist[x] + i.value);
                if (--deg[i.to] == 0) q.push(i.to);
            }
            q.pop();
        }
        return max(0LL, dist[t]);
    }
} res, zys;
int n, m;
int main()
{
    // freopen("Reszys.in", "r", stdin);
    // freopen("Reszys.out", "w", stdout);
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d", &n, &m);
        res.init(n), zys.init(n);
        for (int i = 1; i <= m; i ++)
        {
            int u, v, c, r, z;
            scanf("%d%d%d%d%d", &u, &v, &c, &r, &z);
            res.add_edge(u, v, c - r);
            zys.add_edge(u, v, c - z);
        }
        long long ans1=res.solve(1, n),ans2=zys.solve(1, n);
        if (ans1>ans2)
            printf("rip!!!\n%lld\n",ans1-ans2);
        if (ans1==ans2) printf("oof!!!\n");
        if (ans1<ans2) printf("cnznb!!!\n%lld\n",ans2-ans1);
    }
    return 0;
}