邮局村庄问题,n个村庄m个邮局,每个村庄都要去一个离自己最近的邮局,求村庄到邮局的最短总距离
邮局村庄问题,n个村庄m个邮局,每个村庄都要去一个离自己最近的邮局,求村庄到邮局的最短总距离
输入 n,m village
输出 最短距离
该问题是区间dp,首先假设只有一个邮局,则将邮局放在村庄数量的中位数位置可以得到最短距离,
设dis[i][j]
表示第i
到j
个村庄之间放一个邮局的最短距离,通过下面递推式可以得到任意两村庄之间设置一个邮局的最短距离:
dis[i][j] = dis[i][j-1] + village[j] - village[(i+j)/2]
设dp[i][j]
表示前i
个村庄分布j
个邮局的最短距离,则:
dp[i][j] = dp[k][j-1] + dis[k+1][i]
即i
个村庄设置j
个邮局的最短距离等于1
到k
个村庄j-1
个邮局的最短距离加上k+1
到i
个村庄设置一个邮局的距离,循环前i
个村庄的k
,即可求出最优解。
代码如下
package main
import "fmt"
// 村庄邮局问题, n个村庄, m个邮局, 村庄直线排列, 问如何分布邮局使得村庄到邮局的距离最短
//
func main() {
n, m := 5, 2
village := []int{1, 2, 3, 4, 5}
// dis[i][j] 表示第i-j村庄之间有 1 个邮局的最短距离
// 可以证明 邮局 位于 i j 中位数之间时 距离最短
// 因此 dis[i][j] = dis[i][j-1] + village[j] - village[(i+j)/2]
dis := make([][]int, n+1)
for i := range dis {
dis[i] = make([]int, n+1)
}
for i := 1; i <= n; i++ {
for j := i; j <= n; j++ {
dis[i][j] = dis[i][j-1] + village[j-1] - village[(i-1+j-1)/2]
}
}
//for _, dis := range dis {
// fmt.Println(dis)
//}
// [0 0 0 0 0 0]
// [0 0 1 2 4 6]
// [0 0 0 1 2 4]
// [0 0 0 0 1 2]
// [0 0 0 0 0 1]
// [0 0 0 0 0 0]
// dp[i][j] 表示前i个村庄分布j个邮局的最优解
// dp[i][j] = dp[i-k][j-1] + dis[i-k][i]
// 枚举 邮局数量j来更新dp
dp := make([][]int, n+1)
for i := 0; i <= n; i++ {
dp[i] = make([]int, m+1)
dp[i][1] = dis[1][i]
}
for j := 2; j <= m; j++ {
for i := j; i <= n; i++ {
dp[i][j] = 1000007
for k := j - 1; k < i; k++ {
dp[i][j] = min(dp[i][j], dp[k][j-1]+dis[k+1][i])
}
}
}
for _, dp := range dp {
fmt.Println(dp)
}
//[0 0 0]
//[0 0 0]
//[0 1 1]
//[0 2 2]
//[0 4 3]
//[0 6 4]
}
func min(a, b int) int {
if a > b {
return b
}
return a
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具