看到这个题,原本想先从后往前dfs,求出能到终点的点,再在这些点里从前往后spfa,用一条边上的两个城市的商品价格的差来作边权,实施过后,发现图中既有负边权,又有回路,以及各种奇奇怪怪的东西。说实话我连样例都没过,然后提交一下试试,得了10分。
然而我发现,要求赚最多钱,就是到那个点的路径上的最大价格 - 最小价格。
两边dfs——
最小价格可以从前往后搜来算。
最大价格可以从后往前搜来算。
最后枚举一边所有点maxx - minn的最大值就好。
说出来你可能不信,我是看的题解。
——代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #include <queue> #include <iostream> using namespace std; int n, m, cnt1, cnt2, ans; int a[100001], next1[1000001], to1[1000001], head1[100001], next2[1000001], to2[1000001], head2[100001], maxx[100001], minn[100001]; inline void add1(int x, int y) { to1[cnt1] = y; next1[cnt1] = head1[x]; head1[x] = cnt1++; } inline void add2(int x, int y) { to2[cnt2] = y; next2[cnt2] = head2[x]; head2[x] = cnt2++; } inline void dfs2(int u, int k) { int i, v; maxx[u] = max(maxx[u], k); for(i = head2[u]; i != -1; i = next2[i]) { v = to2[i]; if(maxx[v] < k) dfs2(v, max(k, a[v])); } } inline void dfs1(int u, int k) { int i, v; minn[u] = min(minn[u], k); for(i = head1[u]; i != -1; i = next1[i]) { v = to1[i]; if(minn[v] > k) dfs1(v, min(k, a[v])); } } int main() { int i, j, x, y, z; memset(head1, -1, sizeof(head1)); memset(head2, -1, sizeof(head2)); scanf("%d %d", &n, &m); for(i = 1; i <= n; i++) { scanf("%d", &a[i]); maxx[i] = -1e9; minn[i] = 1e9; } for(i = 1; i <= m; i++) { scanf("%d %d %d", &x, &y, &z); if(z == 2) { add1(x, y); add1(y, x); add2(x, y); add2(y, x); } else { add1(x, y); add2(y, x); } } dfs1(1, a[1]); dfs2(n, a[n]); for(i = 1; i <= n; i++) ans = max(ans, maxx[i] - minn[i]); printf("%d", ans); return 0; }
其中dfs不用设置vis来记录是否被访问过,因为有双向道路,所以走到一个点有可能会返回来,所以进行深搜的判断标准是目标点(姑且这么说吧)的最大最小值小于或大于当前点的最大最小值。这样即使走到后面的点,发现前面的点需要修改,也可以改回去。
也可以用 spfa ,改变一下松弛操作,dis 数组表示到当前点的路径上买入的最小值,最后统计一遍就行。
——代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 6 using namespace std; 7 8 const int MAXN = 200001; 9 int n, m, cnt, cnt1, ans; 10 int a[MAXN], head[MAXN], to[MAXN], next[MAXN], head1[MAXN], to1[MAXN], next1[MAXN], dis[MAXN]; 11 bool b[MAXN], vis[MAXN]; 12 queue <int> q; 13 14 inline void add(int x, int y) 15 { 16 to[cnt] = y; 17 next[cnt] = head[x]; 18 head[x] = cnt++; 19 } 20 21 inline void add1(int x, int y) 22 { 23 to1[cnt1] = y; 24 next1[cnt1] = head1[x]; 25 head1[x] = cnt1++; 26 } 27 28 inline void dfs(int u) 29 { 30 int i, v; 31 b[u] = 1; 32 for(i = head1[u]; i != -1; i = next1[i]) 33 { 34 v = to1[i]; 35 if(!b[v]) dfs(v); 36 } 37 } 38 39 inline void spfa(int u) 40 { 41 int i, v; 42 memset(dis, 127 / 3, sizeof(dis)); 43 q.push(u); 44 dis[u] = a[u]; 45 while(!q.empty()) 46 { 47 u = q.front(); 48 q.pop(); 49 vis[u] = 0; 50 for(i = head[u]; i != -1; i = next[i]) 51 { 52 v = to[i]; 53 if(dis[v] > min(dis[u], a[v]) && b[v]) 54 { 55 dis[v] = min(dis[u], a[v]); 56 if(!vis[v]) 57 { 58 q.push(v); 59 vis[v] = 1; 60 } 61 } 62 } 63 } 64 } 65 66 int main() 67 { 68 int i, j, x, y, z; 69 scanf("%d %d", &n, &m); 70 for(i = 1; i <= n; i++) scanf("%d", &a[i]); 71 memset(head, -1, sizeof(head)); 72 memset(head1, -1, sizeof(head1)); 73 for(i = 1; i <= m; i++) 74 { 75 scanf("%d %d %d", &x, &y, &z); 76 if(z == 1) 77 { 78 add(x, y); 79 add1(y, x); 80 } 81 else 82 { 83 add(x, y); 84 add(y, x); 85 add1(x, y); 86 add1(y, x); 87 } 88 } 89 dfs(n); 90 spfa(1); 91 for(i = 1; i <= n; i++) 92 if(b[i]) 93 ans = max(ans, a[i] - dis[i]); 94 printf("%d", ans); 95 return 0; 96 }