ybt 1197:山区建小学
OpenJudge NOI 2.6 7624:山区建小学
洛谷 P4677 山区建小学
现在准备在第i村到第j村中建立一所小学,从第i村到第j村的学生都只能上这一所小学。考虑将小学建在哪个村里,可以使得第i到第j各村的学生上学距离加和最短?
上图用一条线段上的点表示各个村,包括第i,i+1,i+2,…,j-1,j村。
相邻两村之间的距离是已知的,已知第 x x x到第 x + 1 x+1 x+1村的距离为 d x d_x dx,设在第p村建学校。
证明: p = i + j 2 p=\frac{i+j}{2} p=2i+j时,在第 p p p村建学校,各村上学的距离总和最小。
引理1:将学校从第k-1村移到第k村,上学总距离减少: s d = ( i + j + 1 − 2 k ) d k − 1 sd=(i+j+1-2k)d_{k-1} sd=(i+j+1−2k)dk−1
证明:考虑特殊情况:
- 如果 p = i p=i p=i,那么总距离加和为: ∑ y = i j − 1 ( ∑ x = i y d x ) \sum_{y=i}^{j-1}(\sum_{x=i}^{y}d_x) ∑y=ij−1(∑x=iydx)
- 如果 p = i + 1 p=i+1 p=i+1,相比于 p = i p=i p=i,从 i i i村距离0, i + 1 i+1 i+1村距离 d i d_i di,变为 i + 1 i+1 i+1村距离0, i i i村距离增加 d i d_i di,这部分的距离没变。从第 i + 2 i+2 i+2到 j j j村每个村的距离都减少了 d i d_i di,总共减少距离 ( j − i − 1 ) d i (j-i-1)d_i (j−i−1)di
- 如果 p = i + 2 p=i+2 p=i+2,相比于 p = i + 1 p=i+1 p=i+1,原来 i + 2 i+2 i+2村的距离变为 i + 1 i+1 i+1村的距离, i i i村的距离增加 d i + 1 d_{i+1} di+1,从第 i + 3 i+3 i+3到 j j j每个村距离减少 d i + 1 d_{i+1} di+1,全部加起来总共减少 ( j − i − 3 ) d i + 1 (j-i-3)d_{i+1} (j−i−3)di+1
考虑一般情况:
- 如果 p = k p=k p=k,相比于 p = k − 1 p=k-1 p=k−1,原来 k k k村的距离变为 k − 1 k-1 k−1村的距离,
从第 i i i到 k − 2 k-2 k−2村每村上学距离增加了 d k − 1 d_{k-1} dk−1,共增加距离 ( k − i − 1 ) d k − 1 (k-i-1)d_{k-1} (k−i−1)dk−1。
从第 k + 1 k+1 k+1到 j j j村每村上学距离减少了 d k − 1 d_{k-1} dk−1,共减少距离 ( j − k ) d k − 1 (j-k)d_{k-1} (j−k)dk−1。
总减少距离 s d sd sd为 ( j − k ) d k − 1 − ( k − i − 1 ) d k − 1 (j-k)d_{k-1}-(k-i-1)d_{k-1} (j−k)dk−1−(k−i−1)dk−1
即将学校从第k-1村移到第k村,总距离减少: s d = ( i + j + 1 − 2 k ) d k − 1 sd=(i+j+1-2k)d_{k-1} sd=(i+j+1−2k)dk−1证明: p = i + j 2 p=\frac{i+j}{2} p=2i+j时,在第 p p p村建学校,各村上学的距离总和最小。
考虑从 i i i到 j j j的数字个数的奇偶性
- 如果从 i i i到 j j j一共有偶数个数字,那么 i , j i,j i,j奇偶性不同, i + j + 1 i+j+1 i+j+1为偶数,能整除2。
- 如果 k < i + j + 1 2 k <\frac{i+j+1}{2} k<2i+j+1,那么 s d = ( i + j + 1 − 2 k ) d k − 1 > 0 sd = (i+j+1-2k)d_{k-1} > 0 sd=(i+j+1−2k)dk−1>0,将学校从 k − 1 k-1 k−1村移动到 k k k村后总距离减少。
- 如果 k = i + j + 1 2 k=\frac{i+j+1}{2} k=2i+j+1,从 k − 1 k-1 k−1村移动到 k k k村距离不变。
- 如果 k > i + j + 1 2 k>\frac{i+j+1}{2} k>2i+j+1,那么 s d = ( i + j + 1 − 2 k ) d k − 1 < 0 sd = (i+j+1-2k)d_{k-1} < 0 sd=(i+j+1−2k)dk−1<0,减少的距离为负值,即为增加距离。将学校从 k − 1 k-1 k−1村移动到 k k k村后的总距离增加。
- 因此在第 i + j − 1 2 \frac{i+j-1}{2} 2i+j−1或 i + j + 1 2 \frac{i+j+1}{2} 2i+j+1村,建学校可以让距离总和最小。考虑整除运算,此时 i + j 2 = i + j − 1 2 \frac{i+j}{2}=\frac{i+j-1}{2} 2i+j=2i+j−1,所以也可以说在第 i + j 2 \frac{i+j}{2} 2i+j村建学校可以使得距离总和最小。
- 如果从 i i i到 j j j一共有奇数个数字,那么 i , j i,j i,j奇偶性相同, i + j i+j i+j为偶数。
- k k k取 i + j 2 \frac{i+j}{2} 2i+j时,减少距离 s d = d k − 1 > 0 sd=d_{k-1}>0 sd=dk−1>0,即将学校从第 i + j 2 − 1 \frac{i+j}{2}-1 2i+j−1村移到 i + j 2 \frac{i+j}{2} 2i+j村,总距离减少。
- k k k取 i + j 2 + 1 \frac{i+j}{2}+1 2i+j+1时,减少距离 s d = − d k − 1 < 0 sd=-d_{k-1}<0 sd=−dk−1<0,即将学校从第 i + j 2 \frac{i+j}{2} 2i+j村移到 i + j 2 + 1 \frac{i+j}{2}+1 2i+j+1村,总距离增加。
- 因此在第 i + j 2 \frac{i+j}{2} 2i+j村建学校,距离总和最小。
c i , j c_{i,j} ci,j表示从第i村到第j村建只一所小学,且从第i村到第j村都上这一所小学,上学的距离加和的最小值。根据上述结论,应该在第 i + 1 2 \frac{i+1}{2} 2i+1村建小学。
记 s i s_i si表示第i村到第1村的距离,那么 s i = ∑ x = 1 i − 1 d x s_i=\sum_{x=1}^{i-1}d_x si=∑x=1i−1dx
那么第i村到第j村的距离 ∑ x = i j − 1 d x \sum_{x=i}^{j-1}d_x ∑x=ij−1dx为 s j − s i s_j-s_i sj−si,类似前缀和。
该问题可以作为一个小的动态规划问题来解, c i , j c_{i,j} ci,j为状态
因此得到状态转移方程为: c i , j = c i , j − 1 + s j − s ( i + j ) / 2 c_{i,j}=c_{i,j-1}+s_j-s_{(i+j)/2} ci,j=ci,j−1+sj−s(i+j)/2
即c[i][j] = c[i][j-1] + s[j] - s[(i+j)/2]
另一种写法,也可以直接通过前缀和求c数组。
求从第i村到第j村每个村到第 i + 1 2 \frac{i+1}{2} 2i+1村的距离加和
c i , j = ∑ x = i ( i + j ) / 2 − 1 ( s ( i + j ) / 2 − s x ) + ∑ x = ( i + j ) / 2 + 1 j ( s x − s ( i + j ) / 2 ) c_{i,j} = \sum_{x=i}^{(i+j)/2-1}(s_{(i+j)/2}-s_x)+\sum_{x=(i+j)/2+1}^{j}(s_x-s_{(i+j)/2}) ci,j=∑x=i(i+j)/2−1(s(i+j)/2−sx)+∑x=(i+j)/2+1j(sx−s(i+j)/2)
本质上和第一种写法是一样的。由该式也可以推出上述递推公式。
dp[i][j]
: 前i个村建j所小学,且前i个村就只去这j所小学的情况下,各村到最近学校的距离和。dp[i][1] = c[1][i]
dp[i][j] = dp[i-1][j-1]+c[i][i]
dp[i][j] = dp[i-2][j-1]+c[i-1][i]
前i-3个村建j-1所小学,第j所小学给第i-2到第i村使用。dp[i][j] = dp[i-3][j-1]+c[i-2][i]
c[k+1][i]
。所以总加和为:dp[i][j] = dp[k][j-1]+c[k+1][i]
dp[i][j] = dp[k][j-1]+c[k+1][i]
的最小值。前i个村建j所小学,有m个村,最多n个小学。
i从1循环到m,j从1循环到n。如果 j > = i j>=i j>=i,可以保证每个村一所学校,总距离为0。所以j只需要循环到 i − 1 i-1 i−1即可。所以j的循环条件为 j < = n j<=n j<=n且 j < i jj<i。
#include
using namespace std;
#define N 505
#define INF 0x3f3f3f3f
int d[N], s[N];//d[i]:第i村到第i+1村的距离 s[i]:第i村到第1村的距离
int c[N][N];//c[i][j]:第i村到第j村建1所小学,且都上这所小学的最小距离
int dp[N][N];//dp[i][j]:前i个村建j所小学,且都上这些小学的最小距离
int main()
{
int n, m;
cin >> m >> n;
for(int i = 1; i <= m - 1; ++i)
{
cin >> d[i];
s[i+1] = s[i] + d[i];
}
for(int i = 1; i <= m; ++i)
for(int j = i; j <= m; ++j)
c[i][j] = c[i][j-1] + s[j] - s[(i+j)/2];
for(int i = 1; i <= m; ++i)
dp[i][1] = c[1][i];
for(int i = 1; i <= m; ++i)
for(int j = 2; j <= n && j < i; ++j)
{
dp[i][j] = INF;
for(int k = j - 1; k <= i - 1; ++k)
dp[i][j] = min(dp[i][j], dp[k][j-1] + c[k+1][i]);
}
cout << dp[m][n];
return 0;
}
#include
using namespace std;
#define N 505
#define INF 0x3f3f3f3f
int d[N], s[N];//d[i]:第i村到第i+1村的距离 s[i]:第i村到第1村的距离
int c[N][N];//c[i][j]:第i村到第j村建1所小学,且都上这所小学的最小距离
int dp[N][N];//dp[i][j]:前i个村建j所小学,且都上这些小学的最小距离
int main()
{
int n, m;
cin >> m >> n;
for(int i = 1; i <= m - 1; ++i)
{
cin >> d[i];
s[i+1] = s[i] + d[i];
}
for(int i = 1; i <= m; ++i)
for(int j = i; j <= m; ++j)
{
int mid = (i+j)/2;
for(int k = i; k <= mid-1; ++k)
c[i][j] += s[mid] - s[k];
for(int k = mid+1; k <= j; ++k)
c[i][j] += s[k] - s[mid];
}
for(int i = 1; i <= m; ++i)
dp[i][1] = c[1][i];
for(int i = 1; i <= m; ++i)
for(int j = 2; j <= n && j < i; ++j)
{
dp[i][j] = INF;
for(int k = j - 1; k <= i - 1; ++k)
dp[i][j] = min(dp[i][j], dp[k][j-1] + c[k+1][i]);
}
cout << dp[m][n];
return 0;
}