动态规划——openjudge7624山区建小学
2017-07-05 09:01
281 查看
题目:
描述
政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m。为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 )。请根据给定的m、n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。
输入
第1行为m和n,其间用空格间隔
第2行为(m-1) 个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。
例如
10 3
2 4 6 5 2 4 3 1 3
表示在10个村庄建3所学校。第1个村庄与第2个村庄距离为2,第2个村庄与第3个村庄距离为4,第3个村庄与第4个村庄距离为6,…,第9个村庄到第10个村庄的距离为3。
输出
各村庄到最近学校的距离之和的最小值。
样例输入
10 2
3 1 3 1 1 1 1 1 3
样例输出
18
来源
元培-From Whf
所属专栏:戳我访问
山区建小学不是《信息学奥赛一本通第5版》的例题,是noi官方题库的题目。
这题用动态规划来解决,这里需要一个辅助的数组dist,dist[i][j]表示在从i到j这一段区间建一所小学,i到j的村庄都到这个学校来上学的路程和。
分析:
这里采用之前讲到过的分析的方法来分析
状态表达:f[i][j]表示前i个村庄建j所学校,到里那个村庄最近的学校上学的路程和。
状态转移:
状态数量:n^2
转移代价:O(n)
时间复杂度:O(n^3)
空间复杂度:O(n^2)(忽略常数)
分析完毕。
还有一点,就是有关如何求dist数组的,其实,我们可以发现,在i到j村庄里建小学,一定是最优的。画个图你就懂了。
如何快速求dist呢,其实,dist[i][j]等于dist[i][j-1]+num[j]-num[i+j]/2的,建议画个图。
代码:
描述
政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m。为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 )。请根据给定的m、n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。
输入
第1行为m和n,其间用空格间隔
第2行为(m-1) 个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。
例如
10 3
2 4 6 5 2 4 3 1 3
表示在10个村庄建3所学校。第1个村庄与第2个村庄距离为2,第2个村庄与第3个村庄距离为4,第3个村庄与第4个村庄距离为6,…,第9个村庄到第10个村庄的距离为3。
输出
各村庄到最近学校的距离之和的最小值。
样例输入
10 2
3 1 3 1 1 1 1 1 3
样例输出
18
来源
元培-From Whf
所属专栏:戳我访问
山区建小学不是《信息学奥赛一本通第5版》的例题,是noi官方题库的题目。
这题用动态规划来解决,这里需要一个辅助的数组dist,dist[i][j]表示在从i到j这一段区间建一所小学,i到j的村庄都到这个学校来上学的路程和。
分析:
这里采用之前讲到过的分析的方法来分析
状态表达:f[i][j]表示前i个村庄建j所学校,到里那个村庄最近的学校上学的路程和。
状态转移:
f[i][j] = std::min(f[i][j],f[k][j-1]+dist[k+1][i]),也就是:
for(int i = 1;i<=n;i++) for(int j = 1;j<i;j++) for(int k = 1;k<i;k++) f[i][j] = std::min(f[i][j],f[k][j-1]+dist[k+1][i]);
状态数量:n^2
转移代价:O(n)
时间复杂度:O(n^3)
空间复杂度:O(n^2)(忽略常数)
分析完毕。
还有一点,就是有关如何求dist数组的,其实,我们可以发现,在i到j村庄里建小学,一定是最优的。画个图你就懂了。
如何快速求dist呢,其实,dist[i][j]等于dist[i][j-1]+num[j]-num[i+j]/2的,建议画个图。
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> int num[1001],dist[1001][1001],f[1001][1001]; int main() { int n,m; std::cin>>n>>m; for(int i = 2;i<=n;i++){std::cin>>num[i];num[i] += num[i-1];} for(int i = 1;i<=n;i++) for(int j = i;j<=n;j++) dist[i][j] = dist[i][j-1]+num[j]-num[(i+j)/2]; memset(f,0x3f,sizeof(f)); for(int i = 1;i<=n;i++)f[i][1] = dist[1][i]; for(int i = 1;i<=n;i++) for(int j = 1;j<i;j++) for(int k = 1;k<i;k++) f[i][j] = std::min(f[i][j],f[k][j-1]+dist[k+1][i]); std::cout<<f [m]; return 0; }
相关文章推荐
- 动态规划
- [动态规划]保存子问题的结果
- 【动态规划(二)】迪杰斯特拉算法与普里姆算法
- 【动态规划】Formula 1
- 凸多边形最优三角剖分-动态规划
- 动态规划中级教程 279. Perfect Squares
- 【动态规划】print article
- 编辑距离算法——动态规划
- C - Monkey and Banana (动态规划)
- poj 2385 动态规划
- poj 1163 The Triangle 动态规划
- 【hdu1069】Monkey and Banana (动态规划)
- POJ 1088 动态规划
- 动态规划——树规
- bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划
- 【状态压缩】【动态规划】坑爹题
- [置顶] 【动态规划】求二维数组从左下到右上的最优路径
- Cow Bowling(动态规划)
- HDU-1003 Max Sum 动态规划
- hdu 5464 Clarke and problem 动态规划