目录
回头:
题目大意:
思路解析:
代码实现:
回头:
题目大意:
给你一个n个点m条边的带权有向图,你现在需要从第一个点走到第n个点,求最短路径,当无解时输出-1. 值得注意的是你拥有一个可以无限使用的技能,如果你现在 在x结点前往y结点,你可以将y的任意一条出现永久修改为x->y的边(权值和之前保持一样)。
思路解析:
那我们可以注意到如果我们最终答案包含x->y这个值我们才需要将y的某一条出边修改为x->y,修改之后y就不能再通过这条边了。那如果我们在x->y的过程中就决定修改那条边的话,我们需要维护一个我们前往的y结点信息,和y结点哪个路径无法使用了,这样维护的信息开销太大,变为n^3,不可接受。
但是如果我们在x结点只决定他需不需要当前x->y这个路径,那么就变为了dp[n][2]可以接受,但是如果我们不要的时候就直接加上当前这个路径权值,那我们之后还要删除,需要维护一个要删除的信息,这个是没有必要的,我们直接不加这个值,在下一次进行补充。(我们只需要维护一个欠费的信息即现在还有一条边的权值没有加上去)最多只能欠一次(补充之后,才能继续欠费)。
在x欠费的情况下,假如 x->y, y可以到其余k个结点, (y到这k个结点的路径权值排序为 s0 s1 .... sk) 当我们选择s0这个路径前往下一个结点时,我们应当通过s1的值来进行补充,其余情况下我们应当使用s0的值进行补充。 (所以我们在维护这个有向图时,我们应当对整个路径权值进行排序)。
代码实现:
import java.io.*;
import java.util.*;public class Main {static Vector<Node> g[];static long inf = (long) 1e18;public static void main(String[] args) throws IOException {int n = input.nextInt();int m = input.nextInt();g = new Vector[n+1];for (int i = 0; i < n + 1; i++) {g[i] = new Vector<>();}for (int i = 0; i < m; i++) {int x = input.nextInt();int y = input.nextInt();int val = input.nextInt();g[x].add(new Node(y, val));}long[][] dp = new long[n+1][2];for (int i = 0; i < n + 1; i++) {Arrays.fill(dp[i], inf);}dp[1][0] = 0;dp[1][1] = inf;for (int i = 1; i <= n; i++) {g[i].sort(new Comparator<Node>() {@Overridepublic int compare(Node o1, Node o2) {if (o1.val != o2.val) return o1.val - o2.val;else return o1.x - o2.x;}});}PriorityQueue<Pa> pas = new PriorityQueue<>(new Comparator<Pa>() {@Overridepublic int compare(Pa o1, Pa o2) {if (o1.val != o2.val){if (o1.val > o2.val) return 1;else return -1;}else if (o1.x != o2.x) return o1.x - o2.x;else return o1.st - o2.st;}});// 0 代表每欠费 1代表欠费pas.add(new Pa(1, 0, 0));while (!pas.isEmpty()){Pa cur = pas.poll();if (dp[cur.x][cur.st] < cur.val) continue;if (cur.st == 0){for (int i = 0; i < g[cur.x].size(); i++) {Node ne = g[cur.x].get(i);int y = ne.x;int val = ne.val;if (dp[cur.x][cur.st] + val < dp[y][0]){dp[y][0] = dp[cur.x][cur.st] + val;pas.add(new Pa(y, dp[y][0], 0));}if (dp[cur.x][cur.st] < dp[y][1]){dp[y][1] = dp[cur.x][cur.st];pas.add(new Pa(y, dp[y][1], 1));}}}else {for (int i = 0; i < g[cur.x].size(); i++) {Node ne = g[cur.x].get(i);int y = ne.x;int val = ne.val;if (i == 0 && i + 1 < g[cur.x].size()){if (dp[cur.x][cur.st] + val + g[cur.x].get(1).val < dp[y][0]){dp[y][0] = dp[cur.x][cur.st] + val + g[cur.x].get(1).val;pas.add(new Pa(y, dp[y][0], 0));}if (dp[cur.x][cur.st] + g[cur.x].get(1).val < dp[y][1]){dp[y][1] = dp[cur.x][cur.st] + g[cur.x].get(1).val;pas.add(new Pa(y, dp[y][1], 1));}}else if (i > 0){if (dp[cur.x][cur.st] + val + g[cur.x].get(0).val < dp[y][0]){dp[y][0] = dp[cur.x][cur.st] + val + g[cur.x].get(0).val;pas.add(new Pa(y, dp[y][0], 0));}if (dp[cur.x][cur.st] + g[cur.x].get(0).val < dp[y][1]){dp[y][1] = dp[cur.x][cur.st] + g[cur.x].get(0).val;pas.add(new Pa(y, dp[y][1], 1));}}}}}long ans = dp[n][0];if (g[n].size() >= 1){ans = Math.min(ans, dp[n][1] + g[n].get(0).val);}if (ans >= inf) out.println(-1);else out.println(ans);out.flush();out.close();br.close();}public static class Pa{int x;long val;int st;public Pa(int x, long val, int st) {this.x = x;this.val = val;this.st = st;}}public static class Node{int x;int val;public Node(int x, int val) {this.x = x;this.val = val;}}static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));static Input input = new Input(System.in);static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static class Input {public BufferedReader reader;public StringTokenizer tokenizer;public Input(InputStream stream) {reader = new BufferedReader(new InputStreamReader(stream), 32768);tokenizer = null;}public String next() {while (tokenizer == null || !tokenizer.hasMoreTokens()) {try {tokenizer = new StringTokenizer(reader.readLine());} catch (IOException e) {throw new RuntimeException(e);}}return tokenizer.nextToken();}public int nextInt() {return Integer.parseInt(next());}}
}