-
使用 dp[cnt][p][i] 记录 状态间的转换
-
状态:使用折扣的次数(2),使用折扣的种类(2)
dp[cnt][][]中的cnt–>0:未使用折扣, 1:使用1次折扣, 2:使用2次折扣
dp[][p][]中的p --> 1:使用p1折扣, 0:使用p2折扣
dp[][][i]中的i --> 节点编号
*注意,((成本cost-折扣p)>0)? (成本cost-折扣p) : 0 ;*
使用折扣一定比不使用更小,最后的答案:Math.min(dp[2][1][N], dp[2][0][N])
- 状态转换:
1.折扣的次数
dp[0]–>dp[1]–>dp[2]
2.折扣的种类
dp[0][1]==dp[0][0]
dp[0][1]–>dp[1][0]–>dp[2][1]
dp[0][0]–>dp[1][1]–>dp[2][0]
3.状态转换点
在当前节点时使用折扣–> dp[][][to]> dp[][][cur]+(成本cost-折扣p)
当前节点前已经使用折扣–>dp[][][to]> dp[][][cur]+成本cost
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) throws IOException {
in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int T = nextInt();
for (int i = 0; i <= MaxN; i++) adj.add(new ArrayList<>());
for (int tc = 1; tc <= T; tc++) {
readCase();
work();
System.out.println("#" + tc + " " + Math.min(dp[2][1][N], dp[2][0][N]));
}
}
static void work() {
for (int i = 0; i <= 2; i++) {
for (int j = 0; j < 2; j++) {
Arrays.fill(dp[i][j], 0, N + 1, INF);
}
}
dp[0][0][1] = dp[0][1][1] = 0;
dp[1][0][1] = dp[1][1][1] = 0;
dp[2][0][1] = dp[2][1][1] = 0;
pq.add(new KV(1, 0, 0, 0, 0));
pq.add(new KV(1, 0, 1, 0, 0));
while (!pq.isEmpty()) {
KV fr = pq.poll();
for (int[] to : adj.get(fr.idx)) {
if (fr.fa == to[0]) continue;
//不使用折扣 包括已经使用过折扣
if (dp[fr.cnt][fr.type][to[0]] > fr.cost + to[1]) {
dp[fr.cnt][fr.type][to[0]] = fr.cost + to[1];
pq.add(new KV(to[0], fr.cnt, fr.type, dp[fr.cnt][fr.type][to[0]], fr.idx));
}
//在此时使用折扣
if (fr.cnt < 2) {
int cnt = fr.cnt + 1;
int type = (fr.type == 0) ? 1 : 0;
int cost = (to[1] > P[type]) ? to[1] - P[type] : 0;
if (dp[cnt][type][to[0]] > fr.cost + cost) {
dp[cnt][type][to[0]] = fr.cost + cost;
pq.add(new KV(to[0], cnt, type, dp[cnt][type][to[0]], fr.idx));
}
}
}
}
for (int i = 1; i <= N; i++) adj.get(i).clear();
}
static void readCase() throws IOException {
N = nextInt();
M = nextInt();
P[0] = nextInt();
P[1] = nextInt();
for (int i = 0; i < M; i++) {
int a = nextInt();
int b = nextInt();
int c = nextInt();
adj.get(a).add(new int[]{
b, c});
adj.get(b).add(new int[]{
a, c});
}
}
static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
static final int MaxN = 40000;
static final long INF = Long.MAX_VALUE >> 1;
static final int[] P = new int[2];
static final long[][][] dp = new long[3][2][MaxN + 2];
static final ArrayList<ArrayList<int[]>> adj = new ArrayList<>();
static final PriorityQueue<KV> pq = new PriorityQueue<>(Comparator.comparingLong(KV::getCost));
static StreamTokenizer in;
static int N, M;
static class KV {
int idx, cnt, type, fa;
long cost;
KV(int i, int c, int p, long d, int f) {
idx = i;
cnt = c;
type = p;
cost = d;
fa = f;
}
long getCost() {
return cost;
}
}
}