洛谷P1073_最优贸易
题目描述
分析
题目可以概括为:
关键转化:把"买"和"卖"拆成两个独立的最值问题。对每个城市
:从 号城市到 的路径上,能买到的最低价格; :从 到 号城市的路径上,能卖出的最高价格。
答案就是
正确性:若最优买卖是在
思路:双向 SPFA / BFS
边权不参与计算,转移只是对点权取
- 正向图
从 出发, ; - 反向图
(把所有边反向)从 出发, 。
反向建图的目的是把"从
实现细节:
- 单向边
:正向图加 ,反向图加 ;双向边( )两个方向都加。 - 松弛只会让
单调减小、 单调增大,且都有上下界,因此算法必然收敛。 - 答案初始化为
,对应"不交易"的情况;不可达的城市会让 变成很大的负数,不会影响答案。
复杂度:两遍遍历均为
参考代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 100010, M = 2000010;
int p[N];
int hl[N], hr[N], e[M], ne[M], idx;
int dmin[N], dmax[N];
int st[N];
int n, m;
void add(int h[], int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void spfa(int h[], int dist[], int type) {
queue<int> q;
if (type == 1) {
memset(dmin, 0x3f, sizeof dmin);
dist[1] = p[1];
q.push(1);
} else {
memset(dmax, -0x3f, sizeof dmax);
dist[n] = p[n];
q.push(n);
}
while (q.size()) {
int t = q.front();
q.pop();
st[t] = 0;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (type == 1 && dist[j] > min(dist[t], p[j]) || type == 2 && dist[j] < max(dist[t], p[j])) {
if (type == 1) dist[j] = min(dist[t], p[j]);
else dist[j] = max(dist[t], p[j]);
if (!st[j]) {
q.push(j);
st[j] = 1;
}
}
}
}
}
int main() {
memset(hl, -1, sizeof hl);
memset(hr, -1, sizeof hr);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> p[i];
for (int i = 0; i < m; i++) {
int a, b, c; cin >> a >> b >> c;
add(hl, a, b);
add(hr, b, a);
if (c == 2) {
add(hl, b, a);
add(hr, a, b);
}
}
spfa(hl, dmin, 1);
spfa(hr, dmax, 2);
int res = 0;
for (int i = 1; i <= n; i++) {
res = max(res, dmax[i] - dmin[i]);
}
cout << res << endl;
return 0;
}