本文共 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 n−1个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。
例 如 : 例如: 例如:
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 Floyed−Warshall算法,只是表示的方法不一样,而且因为 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 can′t see me. Y o u c a n ′ t s e e m e {\color{white}\ \ You\ can't\ see\ me} You can′t see me
Y o u c a n ′ t s e e m e . {\color{white} You\ can't\ see\ me.} You can′t see me. Y o u c a n ′ t s e e m e {\color{white}\ \ You\ can't\ see\ me} You can′t see me Y o u c a n ′ t s e e m e . {\color{white} You\ can't\ see\ me.} You can′t see me. Y o u c a n ′ t s e e m e {\color{white}\ \ You\ can't\ see\ me} You can′t see me转载地址:http://jlph.baihongyu.com/