DP POJ1160
2015-08-30 16:21
477 查看
题意:
题目链接有一排村庄,坐标表示村庄的位置。如(1、4、6、10)表示:在这几个点有村庄。现在要在这一排村庄中建立邮局,使得其它村庄到他们最近邮局的距离总和最小。
其中邮局有V个(V<=300),邮局有P个(P<=30)。问怎么设置邮局位置,求出最小距离。
解法:
1.表示方法
dp[ii][jj] : 表示前 ii 个村庄 建 jj 个邮局时距离最小值。sum[i][j][i][j]: 表示第 ii 个村庄到第 jj 个村庄建一个邮局的最小距离。
2. 递推公式的由来
这个题目有点类似于矩阵连乘问题。要求dp[i][j]dp[i][j],假设从kk位置断开,前 kk 个村庄建 j−1j-1个邮局,后面k+1k+1 到 ii 建一个邮局,然后求出断开位置使dp[i][j]dp[i][j] 最小。所以递推关系式如下:dp[i][j]=min(dp[i][j],dp[k][j−1]+sum[k+1][i])dp[i][j] = min(dp[i][j], dp[k][j-1] + sum[k+1][i]);
3.sum[i][j]sum[i][j]的递推
在ii 和 jj之间建一个邮局,显然建在中位数的村庄位置时最小。因为题中村庄的位置已经从小到大排好序,因此只要求出中位数村庄即可(这里与村庄的位置大小无关)。如果村庄有奇数个,比如有三个村庄:x1,x2,x3x_1, x_2, x_3, x1到x2的距离为s1,x2到x3的距离为s2x_1到x_2的距离为s_1, x_2到x_3的距离为s_2, 显然建在x2x_2时距离最小为:s1+s2s_1 + s_2。(可以自己造几个case看看).
如果村庄个数为偶数个,那么建在中间两个位置的距离是一样的。比如:x1,x2,x3,x4x_1, x_2, x_3,x_4, x1到x2的距离为s1,x2到x3的距离为s2,x3到x4的距离为s3x_1到x_2的距离为s_1, x_2到x_3的距离为s_2,x_3到x_4的距离为s_3,那么建在中间两个村庄的距离是一样的。建在x2x_2:s1+2∗s2+s3s_1 + 2*s_2 + s_3,
建在x3x_3:s1+2∗s2+s3s_1 + 2*s_2 + s_3。 建在x1x_1: 3∗s1+2∗s2+s33*s_1 + 2*s_2 + s_3。
因此:在ii到jj之间建一个邮局的最小距离等于在ii到j−1j-1之间建一个邮局的距离最小值加上jj点到中位数村庄的距离。即:sum[i][j]=sum[i][j]+x[j]−x[(i+j)/2]sum[i][j] = sum[i][j] + x[j] - x[(i+j)/2]
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; int dp[300+1][300+1],sum[300+1][300+1]; int s[300+1]; int INF = 100000000; int main() { int V,P; scanf("%d%d",&V,&P); memset(dp,sizeof(dp),0); memset(sum,sizeof(sum),0); memset(s, sizeof(s), 0); for(int i = 1; i<=V; i++) scanf("%d",&s[i]); for(int i = 1; i<V; i++){ for(int j = i+1; j<=V; j++) sum[i][j] = sum[i][j-1] + s[j] - s[(i+j)/2]; } for(int i = 1; i<=V; i++) dp[i][1] = sum[1][i]; for(int j = 2; j<=P; j++){ for(int i = 1; i<=V; i++){ dp[i][j] = INF; for(int k = 1; k<=i; k++) dp[i][j] = min(dp[i][j] ,dp[k][j-1]+sum[k+1][i]); } } printf("%d\n",dp[V][P]); return 0; }
相关文章推荐
- Java Servlet Example
- SDWebImage使用详解
- 打印问题
- 点阵字幕的显示原理
- Servlet Life Cycle
- postgresql 表空间创建、删除
- Deep learnin简介
- [LeetCode][JavaScript]Integer to Roman
- 使用GenyMotion模拟器+抓包工具SRSniffer分析网络请求
- iOS Foundation框架初接触
- iOS“断点”(Break Point)你不知道多强大
- 把PHP的数组变成带单引号的字符串
- 我总结的Android编程规范
- HttpServletRequest和HttpServletResponse详解
- POJ 1743 Musical Theme (后缀数组)
- POJ1459-Power Network-网络流-最大流(EK模板题)
- UIScrollView 实践经验
- 【Java】基础语法
- 顺序表基本操作的代码实现:C++实现
- 在动态引用DLL-A中,当参数是个实体,而实体的属性在另一个DLL-B中。。我们需要得到A这个实体并将其赋值,并将赋值的实体传人DLL-A的方法中。