NOI题库7624 山区建小学(162:Post Office / IOI2000 POST OFFICE [input] )

时间:2023-03-22 10:11:32

7624:山区建小学

Description

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

Input

第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。

Output

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

Sample Input

10 2

3 1 3 1 1 1 1 1 3

Sample Output

18

【思路】

划分型DP。

首先对于ij区间,将学校建在中点位置距离区间内的点最短。

设d[i][j]表示前i个村庄建j所学校的最短距离。则有转移式:

d[i][j]=min{
d[k][j-1]+cost(k+1,i) }  (j-1<= k <i)

转移式表示在区间k+1..i的中点建立一所学校使这个区间内的所有村庄都到这里上学,其中cost为最小距离之和。

【代码】

 #include<iostream>
#include<cstring>
#include<cmath>
using namespace std; const int maxn = +;
const int INF=0x3f3f3f3f; int d[maxn][maxn];
int sum[maxn];
int cost[maxn][maxn];
int n,m; void get_cost()
{
for(int i=;i<=n;i++)
for(int j=i;j<=n;j++)
{
cost[i][j]=;
int mid=i+(j-i)/;
for(int k=i;k<=j;k++) cost[i][j] += abs(sum[mid]-sum[k]);
}
} int dp(int i,int j)
{
int &ans=d[i][j];
if(ans<INF) return ans; if(i<j) return INF;
if(i==j) return ans=; //i==j
if(j==) return ans=cost[][i]; //cost(1,i) for(int k=j-;k<i;k++)
ans=min(ans,dp(k,j-)+cost[k+][i]);
return ans;
} int main() {
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=;i<=n;i++) cin>>sum[i] , sum[i] += sum[i-]; get_cost(); memset(d,0x3f,sizeof(d));
cout<<dp(n,m)<<"\n"; return ;
}