题目链接 https://ac.nowcoder.com/acm/contest/257/C
首先明确,这是一个有向图,但是权值并不在边上,权值在图中的一些顶点上。本题相当于求解的是,从1到n的一条路径,使得路径上的两个按照拓扑序先后经过的点,后经过的点的权值减去先经过的点权值的值最大。
挺绕的,,,慢慢理解。。。
如果直到了从 1 到点 i 最小点权,又知道了从 i 到 n 的最大点权,就可以遍历所有的点,然后从所有的差值中选取最大的即为正确答案。
因此本题转换为求从 1 到所有点的最大点权和 从任意点到 n 的最大点权,对于第一个,可以直接在原图上跑最短路算法,并对最短路做稍稍修改。原本最短路中的松弛操作是
d[x] = min(d[x], d[y] + dist);
但是现在求解的已经不是经过路径上所有权值的和了,而是最小的,因此松弛操作改为
d[x] = min(d[x], min(d[y], price[x]));
对于第二个,可以建反图,在反图上以 n 为源点跑最短路,最后遍历这样两个数组求最大差值即可。
/**
* Author : correct
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
const int N = 100100, M = 500100;
const char* path = "D:\\eclipse for c++ workspace\\test\\src\\in.in";
int head[N], nex[M * 5], to[M * 5], cnt;
int rhead[N];
void add(int* h, int a, int b){
++cnt;
to[cnt] = b;
nex[cnt] = h[a];
h[a] = cnt;
}
int price[N];
int n, m;
int df[N], dt[N];
bool vis[N];
queue<int > q;
void spfa(){
mem(df, 0x3f);
mem(vis, 0);
df[1] = price[1];
q.push(1);
vis[1] = 1;
while (!q.empty()){
int t = q.front();
q.pop();
vis[t] = 0;
for (int i = head[t]; i; i = nex[i]){
int y = to[i];
if (df[y] > min(df[t], price[y])){
df[y] = min(df[t], price[y]);
if (vis[y] == 0){
vis[y] = 1;
q.push(y);
}
}
}
}
}
void rspfa(){
mem(dt, 0);
mem(vis, 0);
dt[n] = price[n];
q.push(n);
vis[n] = 1;
while (q.size()){
int t = q.front();
q.pop();
vis[t] = 0;
for (int i = rhead[t]; i; i = nex[i]){
int y = to[i];
if (dt[y] < max(dt[t], price[y])){
dt[y] = max(dt[t], price[y]);
if (vis[y] == 0){
vis[y] = 1;
q.push(y);
}
}
}
}
}
int main()
{
freopen(path, "r", stdin);
ios::sync_with_stdio(0);
cnt = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++)cin >> price[i];
for (int i = 1; i <= m; i++){
int a, b, c;
cin >> a >> b >> c;
add(head, a, b);
add(rhead, b, a);
if (c == 2)add(head, b, a), add(rhead, b, a);
}
spfa();
rspfa();
int ans = -1;
for (int i = 1; i <= n; i++){
// cout << df[i] << " -> " << dt[i] << "\n";
ans = max(ans, dt[i] - df[i]);
}
cout << ans << "\n";
return 0;
}