第一行有两个整数N,num。分别表示居民点的数量,要建的邮局数量。 接下来一行N个整数表示邮局的坐标。保证坐标递增 6 2 1 2 3 4 5 1000 6 第一个邮局建立在3位置,第二个邮局建立在1000位置。那么1位置到邮局的距离为2,2位置到邮局距离为1,3位置到邮局的距离为0,4位置到邮局的距离为1,5位置到邮局的距离为2,1000位置到邮局的距离为0. 这种方案下的总距离为6。
数组是递增的,如下说明arr[i...j]
选择中间点作为邮局距离是最短点
对于有偶数个,例如[4 15 26 47]
无论选择15还是26效果都是一样的,4个数值三个相邻距离设置为a b c
那么
15 作为邮局:a + b + (b + c) = a + 2b + c
26 作为邮局:(a + b) + b + c = a + 2b + c
新增了一个数(不论原来是奇数个数,还是偶数个数)
[4 15 26 47]
=》 [4,15,26,47,53]
a + 2b + c => a + 2b + c + (c+d) 比原来多了最后一个元素到中间点的距离
[4 15 26]
=》 [4,15,26,47]
a + b => a + 2b + c 比原来多了最后一个元素到中间点的距离
所以有
w[i][j+1] = w[i][j] + arr[j+1] - arr[(i+j)/2]
对于一个元素的w[i][i]
初始都是0
dp[i][j]
:表示arr[0...j]上设置i + 1个邮局,最后的总距离最短是多少
dp[2][5], 已知dp[1][5], 则有很多种选择
前两个邮局可以负责 arr[0..k],k属于[0....5]
dp[1][0] + w[1][5] dp[1][1] + w[2][5] . . . dp[1][4] + w[5][5] dp[1][5] + w[6][5]
dp[2][5] 等于所有方案的最小值即可
dp[i+1][j] = Min{ dp[i][k] + w[k][j] }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.*; public class Main { public static Scanner sc = new Scanner(System.in); public static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); public static void main(String[] args) throws Exception { int n = sc.nextInt(); int num = sc.nextInt(); int[] arr = new int[n]; for(int i=0;i<n;i++){ arr[i] = sc.nextInt(); } System.out.println(solution(n, arr, num)); } static long solution(int n, int[] arr, int num) { int[][] w = new int[n+1][n+1]; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ w[i][j] = w[i][j-1] + arr[j] - arr[(i+j)/2]; } } int[][] dp = new int[num][n]; // 1个邮局的情况 for(int i=0;i<n;i++){ dp[0][i] = w[0][i]; } for(int i=1;i<num;i++){ for(int j=0;j<n;j++){ int minVal = Integer.MAX_VALUE; for(int k=0;k<=j;k++){ minVal = Math.min(minVal, dp[i-1][k] + w[k+1][j]); } dp[i][j] = minVal; } } return dp[num-1][n-1]; } } /* 6 2 1 2 3 4 5 1000 6 */
那么
当邮局为a个,区间为arr[0...b]时,a-1个邮局不必尝试arr[0...l]小的区域了
那么
当邮局为a个,区间为arr[0...b]时,a个邮局不必尝试比arr[0...m]大的区域了
即求dp[a][b]
时,看dp[a-1][b]
的a-2负责的位置,然后再看dp[a][b+1]
的a-1负责的位置
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.*; public class Main { public static Scanner sc = new Scanner(System.in); public static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); public static void main(String[] args) throws Exception { int n = sc.nextInt(); int num = sc.nextInt(); long[] arr = new long[n]; for(int i=0;i<n;i++){ arr[i] = sc.nextLong(); } System.out.println(solution(n, arr, num)); } static long solution(int n, long[] arr, int num) { long[][] w = new long[n+1][n+1]; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ w[i][j] = w[i][j-1] + arr[j] - arr[(i+j)/2]; } } long[][] dp = new long[num][n]; int[][] s = new int[num][n]; // 1个邮局的情况 for(int i=0;i<n;i++){ dp[0][i] = w[0][i]; s[0][i] = 0; } for(int i=1;i<num;i++){ for(int j=n-1;j>=i;j--){ long minVal = Long.MAX_VALUE; int minPos = -1; int kMin = s[i-1][j]; int kMax = j == n-1 ? j : s[i][j+1]; for(int k=kMin;k<=kMax;k++){ if(dp[i-1][k] + w[k+1][j] <= minVal){ minVal = dp[i-1][k] + w[k+1][j]; minPos = k; } } dp[i][j] = minVal; s[i][j] = minPos; } } return dp[num-1][n-1]; } } /* 6 2 1 2 3 4 5 1000 6 */
or
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.*; public class Main { public static Scanner sc = new Scanner(System.in); public static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); public static void main(String[] args) throws Exception { int n = sc.nextInt(); int num = sc.nextInt(); long[] arr = new long[n]; for(int i=0;i<n;i++){ arr[i] = sc.nextLong(); } System.out.println(solution(n, arr, num)); } static long solution(int n, long[] arr, int num) { long[][] w = new long[n+1][n+1]; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ w[i][j] = w[i][j-1] + arr[j] - arr[(i+j)/2]; } } long[][] dp = new long[num][n]; int[] cands = new int[n]; // 1个邮局的情况 for(int i=0;i<n;i++){ dp[0][i] = w[0][i]; } for(int i=1;i<num;i++){ for(int j=n-1;j>=i;j--){ long minVal = Long.MAX_VALUE; int minPos = -1; int kMin = cands[j]; int kMax = j == n-1 ? j : cands[j+1]; for(int k=kMin;k<=kMax;k++){ if(dp[i-1][k] + w[k+1][j] <= minVal){ minVal = dp[i-1][k] + w[k+1][j]; minPos = k; } } dp[i][j] = minVal; cands[j] = minPos; } } return dp[num-1][n-1]; } } /* 6 2 1 2 3 4 5 1000 6 */