题目
国有 个大城市和 条道路,每条道路连接这 个城市中的某两个城市。
任意两个城市之间最多只有一条道路直接相连。
这 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道路在统计条数时也计为 条。
国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。
但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。
商人阿龙来到 国旅游。
当他得知“同一种商品在不同城市的价格可能会不同”这一信息之后,便决定在旅游的同时,利用商品在不同城市中的差价赚一点旅费。
设 国 个城市的标号从 ,阿龙决定从 号城市出发,并最终在 号城市结束自己的旅行。
在旅游的过程中,任何城市可以被重复经过多次,但不要求经过所有 个城市。
阿龙通过这样的贸易方式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另一个城市卖出这个水晶球,用赚取的差价当做旅费。
因为阿龙主要是来 国旅游,他决定这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。
现在给出 个城市的水晶球价格, 条道路的信息(每条道路所连接的两个城市的编号以及该条道路的通行情况)。
请你告诉阿龙,他最多能赚取多少旅费。
注意:本题数据有加强。
输入格式
第一行包含 个正整数 和 ,中间用一个空格隔开,分别表示城市的数目和道路的数目。
第二行 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这 个城市的商品价格。
接下来 行,每行有 个正整数, ,每两个整数之间用一个空格隔开。
如果 ,表示这条道路是城市 到城市 之间的单向道路;如果 ,表示这条道路为城市 和城市 之间的双向道路。
输出格式
一个整数,表示答案。
数据范围
,
,
输入样例:
5 5
4 3 5 6 1
1 2 1
1 4 1
2 3 2
3 5 1
4 5 2
输出样例:
5
解题
方法一:SPFA算法
思路
简化题目:求从 走到 的所有路线中先买后卖能得到的最大收益。
把 的所有路线表示为一个集合,把集合划分为:
其中, 表示:在 中的某个点买入(包括 ),在 的某个点卖出(包括 )的从 走到 的路线集合。
我们发现,这这样划分出的集合可能会有重复,但是绝对不会有遗漏,也就是说可以把每一种情况都枚举到,那么对每一个集合求受益最大值,再对所有集合的最大值求一次最大值就可以得到答案最大收益。
求每一类划分集合的最大值:以 为例,就是求在点 前面买入,后面卖出的最大收益。求该最大收益可以使用分段的方式来求:
- 先求出 中的最小权值点用于买入( );
- 再求出 中的最大权值点用于卖出( );
- 作差后得到的就是最大收益( )。
在求 和 时,由于不是拓扑图,状态的更新可能存在环,因此不能使用动态规划,只能使用求最短路的方式。
另外,我们考虑能否使用 Dijkstra 算法,如果当前 最小的点是 ,那么有可能存在边 ,假设当前 ,则有可能存在 的价格是 , 但 的价格是 ,那么 的值就应该被更新成 ,因此当前最小值也不一定是最终最小值,所以 Dijkstra 算法并不适用,我们只能采用 SPFA 算法。
SPFA 求解时,求 使用正向边,求 需要用反向边。
代码
import java.util.*;
import java.io.*;
public class Main {
static final int INF = 0x3f3f3f3f;
static int n, m;
static int[] w;
// h[0]为求dmin时用的正向边 h[1]为求dmax时的用到反向边
static int[][] h;
static int[] e, ne;
static int idx;
static int[] dists;
static boolean[] has;
static Queue<Integer> que;
static void add(int a, int b, int type) {
e[idx] = b;
ne[idx] = h[type][a];
h[type][a] = idx++;
}
// type==0求dmin type==1求dmax
static int[] spfa(int src, int type) {
Arrays.fill(dists, type == 0 ? INF : -INF);
Arrays.fill(has, false);
dists[src] = w[src];
que.offer(src);
has[src] = true;
while (!que.isEmpty()) {
int u = que.poll();
has[u] = false;
for (int i = h[type][u]; i != -1; i = ne[i]) {
int v = e[i];
boolean updated = false;
if (type == 0 && Math.min(dists[u], w[v]) < dists[v]) {
dists[v] = Math.min(dists[u], w[v]);
updated = true;
} else if (type == 1 && Math.max(dists[u], w[v]) > dists[v]) {
dists[v] = Math.max(dists[u], w[v]);
updated = true;
}
if (updated && !has[v]) {
que.offer(v);
has[v] = true;
}
}
}
return dists.clone();
}
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
n = (int) in.nval;
in.nextToken();
m = (int) in.nval;
w = new int[n + 1];
h = new int[2][n + 1];
Arrays.fill(h[0], -1);
Arrays.fill(h[1], -1);
e = new int[m * 4];
ne = new int[m * 4];
dists = new int[n + 1];
has = new boolean[n + 1];
que = new LinkedList<>();
for (int i = 1; i <= n; ++i) {
in.nextToken();
w[i] = (int) in.nval;
}
while (m-- > 0) {
in.nextToken();
int x = (int) in.nval;
in.nextToken();
int y = (int) in.nval;
in.nextToken();
int z = (int) in.nval;
add(x, y, 0);
add(y, x, 1);
if (z== 2) {
add(y, x, 0);
add(x, y, 1);
}
}
int[] dmin = spfa(1, 0), dmax = spfa(n, 1);
int ans = 0;
for (int i = 1; i <= n; ++i) ans = Math.max(ans, dmax[i] - dmin[i]);
System.out.println(ans);
}
}
评论区