P1073 最优贸易 DFS
题意:\(n\)个城市,\(m\)条边(单向或双向)
每个城市对于水晶球有一个价格(买的价格与卖的价格相等)
现在从\(1\)走到\(n\),可重复经过城市,
问能赚到的最大差价(在最小的地方买,最大的地方卖,且只进行一次买卖)
输入边\(a, b, c\)表示a到b有(\(c=1\) 单向 \(c=2\)双向)边
题解:
在这里提供一种只用到DFS的算法
题目可以转化为在图中找两个点权差值最大的点
这两个点要保证从\(1\)到\(n\)遍历时先遍历到点权小的点,再遍历到点权大的点。
设\(maxl[i]\)代表从i到终点能到的最大的点
设\(minl[i]\)代表从起点到i能走到的最小的点
正向建图DFS求\(minl\)
反向建图DFS求\(maxl\)
最后\(ans = max^n_{i=1}(maxl[i]-minl[i])\)
注:在建图时,采用的是一种比较特别的方式。
将所有的边建成双向边。
其中给不同的边附上不同的权值。
正向边边权附\(1\),反向边边权附\(2\)。
双向边边权附\(3\)。
在DFS时进行判断次边是否可走即可
code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1e5 + 5, M = 5e5 + 5;
int ans, z, n, m, cnt;
int head[N], to[M], nxt[M], maxl[N], minl[N], vis[N], tag[M];
void add(int u, int v, int t) {
to[++ cnt] = v;
tag[cnt] = t;
nxt[cnt] = head[u];
head[u] = cnt;
}
void dfs1(int x, int v) {
if(vis[x] == 1) return;
vis[x] = 1;
minl[x] = min(minl[x], v);
for(int i = head[x]; i ;i = nxt[i]) {
int v = to[i];
if(vis[v] == 1||tag[i] == 2) continue;
dfs1(v, minl[x]);
}
}
void dfs2(int x, int v) {
if(vis[x] == 1) return;
vis[x] = 1;
maxl[x] = max(maxl[x], v);
for(int i = head[x]; i ;i = nxt[i]) {
int v = to[i];
if(vis[v] == 1 || tag[i] == 1) continue;
dfs2(v, maxl[x]);
}
ans = max(ans, maxl[x] - minl[x]);
}
int main() {
cin >> n >> m;
for(int i = 1;i <= n;i ++) cin >> minl[i], maxl[i] = minl[i];
for(int i = 1, x, y;i <= m;i ++) {
cin >> x >> y >> z;
if(z == 1) add(x, y, 1), add(y, x, 2);
if(z == 2) add(x, y, 3), add(y, x, 3);
}
dfs1(1, minl[1]);
memset(vis, 0, sizeof(vis));
dfs2(n, maxl[n]);
cout << ans << endl;
return 0;
}
作者:Paranoid丶离殇
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。