题面
思路
动态规划,如果一开始想不到就想想记忆化递归。
- dp[i][j][k],左边到底i个,右边到第j个,k=0或1,0表示在左边,1表示在右边
- 边界为i=0或j=0
for (int i = 1; i <= l; i++) {
dp[i][0][0] = a + ls[i] - ls[1];
dp[i][0][1] = INF;
}
for (int i = 1; i <= r; i++) {
dp[0][i][1] = b + rs[i] - rs[1];
dp[0][i][0] = INF;
}
- 转换方程
i=5时,要得到j=6,k=1的最短路,要么从j-1=5,k=1,上来,也就是右边往上一格,要么j-1=5,k=0,横跨走廊过来,比较两边,取小的。
for (int i = 1; i <= l; i++) {
for (int j = 1; j <= r; j++) {
dp[i][j][0] = Math.min(dp[i - 1][j][0] + ls[i] - ls[i - 1], dp[i - 1][j][1] + f(w, abs(ls[i] - rs[j])));
dp[i][j][1] = Math.min(dp[i][j - 1][0] + f(w, abs(ls[i] - rs[j])), dp[i][j - 1][1] + rs[j] - rs[j - 1]);
}
}
code
import java.util.Scanner;
import static java.lang.Math.sqrt;
import static java.lang.Math.abs;
public class 画廊 {
static int INF = 0x3f3f3f3f;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int l = sc.nextInt();
int r = sc.nextInt();
double d = sc.nextInt();// 长度
double w = sc.nextInt();// 宽度
double wr = w / 2;
int[] ls = new int[l + 1];
int[] rs = new int[r + 1];
for (int i = 1; i <= l; i++) {
ls[i] = sc.nextInt();
}
for (int i = 1; i <= r; i++) {
rs[i] = sc.nextInt();
}
double[][][] dp = new double[l + 1][r + 1][2];
double a = f(wr, ls[1]);
double b = f(wr, rs[1]);
for (int i = 1; i <= l; i++) {
dp[i][0][0] = a + ls[i] - ls[1];
dp[i][0][1] = INF;
}
for (int i = 1; i <= r; i++) {
dp[0][i][1] = b + rs[i] - rs[1];
dp[0][i][0] = INF;
}
for (int i = 1; i <= l; i++) {
for (int j = 1; j <= r; j++) {
dp[i][j][0] = Math.min(dp[i - 1][j][0] + ls[i] - ls[i - 1], dp[i - 1][j][1] + f(w, abs(ls[i] - rs[j])));
dp[i][j][1] = Math.min(dp[i][j - 1][0] + f(w, abs(ls[i] - rs[j])), dp[i][j - 1][1] + rs[j] - rs[j - 1]);
}
}
System.out.printf("%.2f", Math.min(dp[l][r][0] + f(wr, d - ls[l]), dp[l][r][1] + f(wr, d - rs[r])));
}
static double f(double a, double b) {
return sqrt(a * a + b * b);
}
}