算法知识点: SPFA

复杂度:

解题思路:

先求出:

  • 走到 的过程中,买入水晶球的最低价格
  • 走到 的过程中,卖出水晶球的最高价格

然后枚举每个城市作为买卖的中间城市,求出 的最大值即可。

时,由于不是拓扑图,状态的更新可能存在环,因此不能使用动态规划,只能使用求最短路的方式。

C++ 代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std; const int N = 100010,
    M = 2000010;
 
int n, m;
int price[N];
int h[N], rh[N], e[M], ne[M], idx;
int dmax[N], dmin[M];
bool st[N];
 
void add(int *h, int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
 
void spfa(int *d, int sign)
{
    queue<int> q;
    memset(st, false, sizeof st);
    if (sign == 1) memset(d, 0x3f, sizeof dmax);
 
    if (sign == 1) q.push(1), st[1] = true;
    else q.push(n), st[n] = true;
 
    while (q.size())
    {
        int t = q.front();
        q.pop();
 
        for (int i = sign == 1 ? h[t] : rh[t]; ~i; i = ne[i])
        {
            int j = e[i];
 
            if (sign == 1 && d[j] > min(d[t], price[j]) || sign == -1 && d[j] < max(d[t], price[j]))
            {
                if (sign == 1) d[j] = min(d[t], price[j]);
                else d[j] = max(d[t], price[j]);
 
                if (!st[j])
                {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }
}
 
int main()
{
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    memset(rh, -1, sizeof rh);
 
    for (int i = 1; i <= n; i++) scanf("%d", &price[i]);
 
    while (m--)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(h, a, b), add(rh, b, a);
        if (c == 2) add(h, b, a), add(rh, a, b);
    }
 
    spfa(dmin, 1);
    spfa(dmax, -1);
 
    int res = 0;
    for (int i = 1; i <= n; i++) res = max(res, dmax[i] - dmin[i]);
 
    printf("%d\n", res);
 
    return 0;
}


另外,牛客暑期NOIP真题班限时免费报名
报名链接:https://www.nowcoder.com/courses/cover/live/248
报名优惠券:DCYxdCJ