博客
关于我
山区建小学
阅读量:322 次
发布时间:2019-03-04

本文共 2763 字,大约阅读时间需要 9 分钟。

山 区 建 小 学 山区建小学

题目链接:

题目

政府在某山区修建了一条道路,恰好穿越总共 n n n个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为 d i d_i di(为正整数),其中, 0 < i < n 0<i<n 0<i<n。为了提高山区的文化素质,政府又决定从 n n n个村中选择 m m m个村建小学。请根据给定的 n n n m m m以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。

输入

1 1 1行为 n n n m m m,其间用空格间隔。

第2行为 n − 1 n-1 n1个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。

例 如 : 例如:

10   3 10\ 3 10 3

2   4   6   5   2   4   3   1   3 2\ 4\ 6\ 5\ 2\ 4\ 3\ 1\ 3 2 4 6 5 2 4 3 1 3

表示在 10 10 10个村庄中建 3 3 3所学校。第 1 1 1个村庄与第 2 2 2个村庄距离为 2 2 2,第 2 2 2个村庄与第 3 3 3个村庄距离为 4 4 4,第 3 3 3个村庄与第 4 4 4个村庄距离为 6 6 6 . . . ... ...,第 9 9 9个村庄到第 10 10 10个村庄的距离为 3 3 3

输出

各村庄到最近学校的距离之和的最小值。

样例输入

10 23 1 3 1 1 1 1 1 3

样例输出

18

数据范围

0   <   m   < =   n   <   500 0\ <\ m\ <=\ n\ <\ 500 0 < m <= n < 500

0   <   d i   < =   100 0\ <\ d_i\ <=\ 100 0 < di <= 100

思路

这道题是一道动态规划。

要做出这道题,最重要的一部是怎么求出 i i i j j j第之间的所有村庄都到一个学校时,所需要的距离总和的最小值。

那么在这里呢,我们就认为最中间的村庄就是可以让距离总和最小的。我们用 f [ i ] [ j ] f[i][j] f[i][j]表示,在第 i i i个村庄到第 j j j个村庄中只建一个学校所能获得的最小距离总和。那么我们就可以通过前缀和和我们的贪心求出 f f f

接着呢,我们就可以通过 d p dp dp求出答案。至于怎么 d p dp dp呢,很简单,就是这个:

f [ i ] [ j ]   =   m i n ( f [ i ] [ j ] ,   f [ k ] [ j   −   1 ]   +   d i s [ k   +   1 ] [ i ] )   ( j   −   1   < =   k   < =   i ) f[i][j]\ =\ min(f[i][j],\ f[k][j\ -\ 1]\ +\ dis[k\ +\ 1][i])\ (j\ -\ 1\ <=\ k\ <=\ i) f[i][j] = min(f[i][j], f[k][j  1] + dis[k + 1][i]) j  1 <= k <= i
其中, d i s dis dis表示我们之前算出来的距离,而 k k k就表示分界点。
这个其实就是一个 F l o y e d − W a r s h a l l Floyed-Warshall FloyedWarshall算法,只是表示的方法不一样,而且因为 n n n最大只有 500 500 500,所以三重循环是可行的。

代码

#include
#include
#include
#include
using namespace std;int n, m, a[501], dis[501][501], f[501][501];int main() { scanf("%d %d", &n, &m);//读入 for (int i = 2; i <= n; i++) { scanf("%d", &a[i]);//读入 a[i] += a[i - 1];//前缀和 } for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) { int school = (i + j) >> 1;//应该建的位置 for (int k = i; k <= j; k++) dis[i][j] += abs(a[school] - a[k]);//求出距离 } memset(f, 0x7f, sizeof(f));//初始化 f[0][0] = 0;//初始化 for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (j > i) { f[i][j] = 0;//每个地方都可以建学校 continue; } for (int k = j - 1; k <= i; k++) f[i][j] = min(f[i][j], f[k][j - 1] + dis[k + 1][i]);//动态转移方程 } printf("%d", f[n][m]);//输出 return 0;}

Y o u   c a n ′ t   s e e   m e . {\color{white} You\ can't\ see\ me.} You cant see me.    Y o u   c a n ′ t   s e e   m e {\color{white}\ \ You\ can't\ see\ me}   You cant see me

Y o u   c a n ′ t   s e e   m e . {\color{white} You\ can't\ see\ me.} You cant see me.    Y o u   c a n ′ t   s e e   m e {\color{white}\ \ You\ can't\ see\ me}   You cant see me
Y o u   c a n ′ t   s e e   m e . {\color{white} You\ can't\ see\ me.} You cant see me.    Y o u   c a n ′ t   s e e   m e {\color{white}\ \ You\ can't\ see\ me}   You cant see me

转载地址:http://jlph.baihongyu.com/

你可能感兴趣的文章
【Coursera】Internet History 读书笔记
查看>>
《ODAY安全:软件漏洞分析技术》学习心得-----shellcode的一点小小的思考
查看>>
PHP serialize && unserialize Security Risk Research
查看>>
Deformity ASP/ASPX Webshell、Webshell Hidden Learning
查看>>
Decision tree(决策树)算法初探
查看>>
《Unity3D/2D游戏开发从0到1(第二版本)》 书稿完结总结
查看>>
sctf_2019_easy_heap
查看>>
Eclipse 创建 Maven 项目
查看>>
AT 杂题泛做
查看>>
StringBuilder拼接字符串,“,”在前还是在后问题
查看>>
给asterisk1.8.7添加menuselct选项
查看>>
ASP.NET Core分布式项目实战(oauth2 + oidc 实现 server部分)--学习笔记
查看>>
ASP.NET Core分布式项目实战(oauth2 + oidc 实现 client部分)--学习笔记
查看>>
组合模式
查看>>
PyQt5之音乐播放器
查看>>
css居中方法与双飞翼布局
查看>>
Redis进阶实践之十八 使用管道模式提高Redis查询的速度
查看>>
SQL注入
查看>>
XCTF-upload1
查看>>
LeetCode 题解 | 1. 两数之和
查看>>