邮局选址问题
链接:https://www.nowcoder.com/questionTerminal/8b0152848ffd475eaa950278606fe70b
来源:牛客网
一条直线上有居民点,邮局只能建在居民点上。给定一个有序整形数组arr,每个值表示居民点的一维坐标,再给定一个正数num,表示邮局数量。 选择num个居民点建立num个邮局,使所有的居民点到邮局的总距离最短,返回最短的总距离。
import java.util.Map;
import java.util.Scanner;
public class Main {
private static int[][] getRecord(int[] arr) {
int[][] record = new int[arr.length][arr.length];
for (int i = 0; i < arr.length; ++i) {
for (int j = i + 1; j < arr.length; ++j) {
record[i][j] = record[i][j - 1] + arr[j] - arr[(i + j) >> 1];
}
}
return record;
}
/**
* 未优化版本
*
* @param arr
* @param m
* @return
*/
private static int solve(int[] arr, int m) {
if (arr == null || arr.length == 0) {
return 0;
}
int n = arr.length;
int[][] record = getRecord(arr);
m = Math.min(n, m);
int[][] dp = new int[n][m];
for (int i = 0; i < n; ++i) {
dp[i][0] = record[0][i];
}
for (int i = 1; i < n; ++i) {
for (int j = 1; j < Math.min(m, i + 1); ++j) {
dp[i][j] = record[0][i];
for (int s = i; s > 0; --s) {
dp[i][j] = Math.min(dp[i][j], dp[s - 1][j - 1] + record[s][i]);
}
}
}
return dp[n - 1][m - 1];
}
/**
* 四边形不等式优化
*
* @param arr
* @param m
* @return
*/
private static int solvePlus(int[] arr, int m) {
if (arr == null || arr.length == 0) {
return 0;
}
int n = arr.length;
int[][] record = getRecord(arr);
m = Math.min(n, m);
int[][] dp = new int[n][m];
int[][] choose = new int[n][m];
for (int i = 0; i < n; ++i) {
dp[i][0] = record[0][i];
choose[i][0] = (i + 1)/ 2;
}
for (int i = 1; i < n; ++i) {
for (int j = Math.min(m - 1, i); j >= 1; --j) {
dp[i][j] = record[0][i];
int up = j == Math.min(m - 1, i) ? i : Math.min(i, choose[i][j + 1]);
int down = Math.max(1, choose[i - 1][j]);
for (int s = up; s >= down; --s) {
if (dp[i][j] > dp[s - 1][j - 1] + record[s][i]) {
dp[i][j] = dp[s - 1][j - 1] + record[s][i];
choose[i][j] = s;
}
}
}
}
return dp[n - 1][m - 1];
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int n = in.nextInt();
int m = in.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; ++i) {
arr[i] = in.nextInt();
}
System.out.println(solvePlus(arr, m));
}
}
}
心之所向,素履以往 生如逆旅,一苇以航
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!