邮局村庄问题,n个村庄m个邮局,每个村庄都要去一个离自己最近的邮局,求村庄到邮局的最短总距离

邮局村庄问题,n个村庄m个邮局,每个村庄都要去一个离自己最近的邮局,求村庄到邮局的最短总距离

输入 n,m village

输出 最短距离

该问题是区间dp,首先假设只有一个邮局,则将邮局放在村庄数量的中位数位置可以得到最短距离,
dis[i][j] 表示第ij个村庄之间放一个邮局的最短距离,通过下面递推式可以得到任意两村庄之间设置一个邮局的最短距离:
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个邮局的最短距离等于1k个村庄j-1个邮局的最短距离加上k+1i个村庄设置一个邮局的距离,循环前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
}

posted @   Notomato  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示