【NOIP2009】最优贸易
本题在洛谷上的链接:https://www.luogu.org/problem/show?pid=P1073
不得不说,这是道好(难)题。我确实没有秒掉他,还是看了别人的分析过的。大家的做法有很多,什么Tarjan、并查集之类的,因为最近在学最短路,所以选择了SPFA变形的做法。
就像刘汝佳(而不是紫书上,愤怒地偷笑)对Floyd的变形那样,SPFA也可以变形,从而维护其他信息。
我们可以这样想,对于每个可以到达终点的结点,只要得到从起点到他购买水晶球的最小花费(自然可以从起点到达该结点),那么以这个点为卖出点的收益就确定了,可以以此更新最终答案。
问题是怎么获得这个最小花费呢?我们可以通过SPFA算法(其实Dijkstra也可以)的变形,像求最短路那样求出每个结点的最小花费。但这里需要注意一点,每个结点的最小花费可能是用当前点为买入点得到的,也可能是用之前的某个点为买入点得到的。所以我们应该用啷个数值的最小值来更新这个最小花费。
还有,怎么保证结点可以到达终点呢?可以对应原图建一个反图(每条边都相反),从终点开始进行遍历,可以遍历到的点就是可以到达终点的结点。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 6 using namespace std; 7 8 inline int get_num() { 9 int num = 0; 10 char c = getchar(); 11 while (c < '0' || c > '9') c = getchar(); 12 while (c >= '0' && c <= '9') 13 num = num * 10 + c - '0', c = getchar(); 14 return num; 15 } 16 17 const int maxn = 1e5 + 5, maxm = 5e5 + 5, inf = 0x3f3f3f3f; 18 19 int head[maxn], eid, head2[maxn], eid2; 20 21 struct Edge { 22 int v, next; 23 } edge[2 * maxm], edge2[2 * maxm]; 24 25 inline void insert(int u, int v) { 26 edge[++eid].v = v; 27 edge[eid].next = head[u]; 28 head[u] = eid; 29 edge2[++eid2].v = u; 30 edge2[eid2].next = head2[v]; 31 head2[v] = eid2; 32 } 33 34 int n, m, price[maxn], minp[maxn], vis[maxn], ans; 35 36 queue<int> q; 37 38 inline void spfa() { 39 memset(minp, inf, sizeof(minp)); 40 minp[1] = price[1]; 41 q.push(1); 42 vis[1] = 1; 43 while (!q.empty()) { 44 int u = q.front(); 45 q.pop(); 46 vis[u] = 0; 47 for (int p = head[u]; p; p = edge[p].next) { 48 int v = edge[p].v; 49 if (minp[v] > min(minp[u], price[v])) { 50 minp[v] = min(minp[u], price[v]); 51 if (!vis[v]) { 52 q.push(v); 53 vis[v] = 1; 54 } 55 } 56 } 57 } 58 } 59 60 inline void bfs() { 61 q.push(n); 62 vis[n] = 1; 63 while (!q.empty()) { 64 int u = q.front(); 65 q.pop(); 66 ans = max(ans, price[u] - minp[u]); 67 for (int p = head2[u]; p; p = edge2[p].next) { 68 int v = edge2[p].v; 69 if (!vis[v]) { 70 q.push(v); 71 vis[v] = 1; 72 } 73 } 74 } 75 } 76 77 int main() { 78 n = get_num(), m = get_num(); 79 for (int i = 1; i <= n; ++i) price[i] = get_num(); 80 for (int i = 1; i <= m; ++i) { 81 int x = get_num(), y = get_num(), z = get_num(); 82 insert(x, y); 83 if (z == 2) insert(y, x); 84 } 85 spfa(); 86 bfs(); 87 printf("%d", ans); 88 return 0; 89 }