7624  山区建小学

描述

政府在某山区修建了一条道路,恰好穿越总共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
———————————————————分割线——————————————————
Solution : 
令 f ( i , j ) 表示前i个村庄修建j个小学的距离之和的最小值。
状态的转移:
f ( i , j ) = f ( k , j - 1 ) + k 到 j修建 1 个小学最小距离和。
那么,怎么快速的求解k 到 j 的最小距离和???
不难猜到 , k 和 j 的中点就是最短的距离。
详细证明在刘汝佳蓝书。
核心DP方程:
f ( i , j ) = min { f ( i , j )  , f ( k , j - 1 ) + cost ( k + 1 , j ) }
 #include "bits/stdc++.h"

 using namespace std ;
const int INF = ;
const int maxN = 1e3 ; int d [ maxN ] , f [ maxN ][ maxN ] , cost[ maxN ][ maxN ] ; int gmin ( int x , int y ) { return x > y ? y : x ; } inline int INPUT ( ) {
int x = , F = ; char ch = getchar ( ) ;
while ( ch < '' || '' < ch ) { if ( ch == '-' ) F = - ; ch = getchar ( ) ; }
while ( '' <= ch && ch <= '' ) { x = ( x << ) + ( x << ) + ch - '' ; ch = getchar ( ) ; }
return x * F ;
} void calc ( int M ) {//计算cost[ i ][ j ] ,即 i 到 j 修建 1 个小学最小距离和。
for ( int i= ;i<=M ; ++i ) {
for ( int j=i+ ; j<=M ; ++j ){
int Dis = ;
int mid = ( i + j ) >> ;
for ( int k=i ; k<mid ; ++k )Dis += d[mid] - d[k] ;
for ( int k=mid+ ; k<=j ; ++k )Dis += d[k] - d[mid] ;
cost[ i ][ j ] = Dis ;
}
}
} void Init_2 ( int N , int M ) {
for ( int i= ; i<=M ; ++i ) {
for ( int j= ; j<=N ; ++j ) {
if ( j== ) f[ i ][ j ] = cost[ ][ i ] ;
else f[ i ][ j ] = INF ;
}
}
}
void Init_1 ( int M ) {
for ( int i= ; i<=M; ++i )
for ( int j=i+ ; j<=M; ++j )
cost[ i ][ j ] = INF ;
} int main ( ) {
int M = INPUT ( ) , N = INPUT ( ) ;
for ( int i= ; i<=M ; ++i )
d[ i ] = d[ i - ] + INPUT ( ) ;
Init_1( M ) ;
calc ( M ) ;
Init_2 ( N , M ) ;
for ( int i= ; i<=M ; ++i ) {
for ( int j= ; j<=N ; ++j ) {
for ( int k= ; k<i ; ++k ){
f[ i ][ j ] = gmin ( f[ i ][ j ] , f[ k ][ j - ] + cost[ k + ][ i ] ) ;
}
}
}
printf ( "%d\n" , f[ M ][ N ] ) ;
return ;
}

2016-10-20 19:15:13

()

05-02 08:35