Coins Respawn(负环,最短路)

题意

给定N个点M条边的有向图,对于每条边(ui,vi),其边权为ci

假设1号点到N号点的一条路径长度为d,求dT×P的最大值。其中T为路径的边数,P为给定常数。

如果不存在最大值(陷入环中),则输出1

题目链接:https://atcoder.jp/contests/abc137/tasks/abc137_e

数据范围

2N2500
1M5000

思路

对于这种与边数或者点数有关的问题,一个常规的套路是,将每条边的边权或点权减去P

对于每条边,边权减去P,问题就转化成了从1N的最长路。将边权取反,即:Pci,问题可以转化为从1N的最短路问题。

对于不存在最大值的情况,一定是陷入了负环当中。但是这不代表存在负环就一定不存在最大值。因为如果一个点在负环上,但是它并不能通往点N,那么它不会出现在从1N的路径上。

那么我们需要判断的其实是能够通往点N的所有点中,是否存在位于一个负环上的。

因此,算法流程就是:先建立反图,然后通过BFS/DFS找到所有能够通往点N的点;由于可能存在负环,因此使用SPFA算法求出是否存在负环,如果不存在则求出最短路。

注意,使用SPFA算法的时候,从一个点向周围点进行拓展,只需要拓展能够通往点N的点。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 2510, M = 4 * N;

int n, m, p;
int h[N], hs[N], e[M], w[M], ne[M], idx;
int cnt[N], d[N];
bool st[N], connect[N];

void add(int h[], int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

void bfs()
{
    queue<int> que;
    que.push(n);
    connect[n] = true;
    while(que.size()) {
        int t = que.front();
        que.pop();
        for(int i = hs[t]; ~i; i = ne[i]) {
            int j = e[i];
            if(!connect[j]) {
                que.push(j);
                connect[j] = true;
            }
        }
    }
}

int spfa()
{
    queue<int> que;
    memset(d, 0x3f, sizeof d);
    d[1] = 0;
    st[1] = true;
    que.push(1);
    while(que.size()) {
        int t = que.front();
        que.pop();
        st[t] = false;
        for(int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];
            if(connect[j] && d[j] > d[t] + w[i]) {
                d[j] = d[t] + w[i];
                if(!st[j]) {
                    st[j] = true;
                    que.push(j);
                    if(++ cnt[j] > n) return -1;
                }
            }
        }
    }
    return max(0, -d[n]);
}

int main()
{
    scanf("%d%d%d", &n, &m, &p);
    memset(h, -1, sizeof h);
    memset(hs, -1, sizeof hs);
    for(int i = 0; i < m; i ++) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(h, a, b, p - c), add(hs, b, a, 1);
    }
    bfs();
    printf("%d\n", spfa());
    return 0;
}
posted @   pbc的成长之路  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示