zoukankan      html  css  js  c++  java
  • NOI 题库 7624

    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 ) }
     1 #include "bits/stdc++.h" 
     2 
     3 using namespace std ;
     4 const int INF = 214748364 ;
     5 const int maxN = 1e3 ;
     6 
     7 int d [ maxN ] , f [ maxN ][ maxN ] , cost[ maxN ][ maxN ] ;
     8 
     9 int gmin ( int x , int y ) { return x > y ? y : x ; }
    10 
    11 inline int INPUT ( ) {
    12         int x = 0 , F = 1 ; char ch = getchar ( ) ;
    13         while ( ch < '0' || '9' < ch ) { if ( ch == '-' ) F = -1 ; ch = getchar ( ) ; }
    14         while ( '0' <= ch && ch <= '9' ) { x = ( x << 1 ) + ( x << 3 ) + ch - '0' ; ch = getchar ( ) ; }
    15         return x * F ;
    16 }
    17 
    18 void calc ( int M ) {//计算cost[ i ][ j ] ,即 i 到 j 修建 1 个小学最小距离和。
    19         for ( int i=1 ;i<=M ; ++i ) {
    20                 for ( int j=i+1 ; j<=M ; ++j ){
    21                         int Dis = 0 ;
    22                         int mid = ( i + j ) >> 1 ;
    23                         for ( int k=i ; k<mid ; ++k )Dis += d[mid] - d[k] ;
    24                         for ( int k=mid+1 ; k<=j ; ++k )Dis += d[k] - d[mid] ;
    25                         cost[ i ][ j ] = Dis ;
    26                 }
    27         }
    28 }
    29 
    30 void Init_2 ( int N , int M ) {
    31         for ( int i=1 ; i<=M ; ++i ) {
    32                 for ( int j=1 ; j<=N ; ++j ) {
    33                         if ( j==1 ) f[ i ][ j ] = cost[ 1 ][ i ] ;
    34                         else f[ i ][ j ] = INF ;
    35                 }
    36         }
    37 }
    38 void Init_1 ( int M ) {
    39         for ( int i=1 ; i<=M; ++i )
    40                 for ( int j=i+1 ; j<=M; ++j )
    41                         cost[ i ][ j ] = INF ;
    42 }
    43 
    44 int main ( ) {
    45         int M = INPUT ( ) , N = INPUT ( ) ;
    46         for ( int i=2 ; i<=M ; ++i )
    47                 d[ i ] = d[ i - 1 ] + INPUT ( ) ;
    48         Init_1( M ) ;
    49         calc ( M ) ;
    50         Init_2 ( N , M ) ;
    51         for ( int i=1 ; i<=M ; ++i ) {
    52                 for ( int j=2 ; j<=N ; ++j ) {
    53                         for ( int k=0 ; k<i ; ++k ){
    54                                 f[ i ][ j ] = gmin ( f[ i ][ j ] , f[ k ][ j - 1 ] + cost[ k + 1 ][ i ] ) ;
    55                         }
    56                 }
    57         }
    58         printf ( "%d
    " , f[ M ][ N ] ) ;
    59         return 0 ;
    60 }
    View Code

     

    2016-10-20 19:15:13

     

    ()

  • 相关阅读:
    php 本周的起始时间
    获取微信公众号素材模板id
    复活贴
    Net 4.0 Parallel 编程(四) Task(上)
    Windows Phone 实用开发技巧120合集(电子书+源代码)
    Net 4.0 Parallel 编程(九)Task中的数据共享(下)
    收藏别人的小类库
    将DLL程序集加入GAC后的一系列问题汇总,及解决方法
    Net 4.0 Parallel 编程(七)Task中的数据共享(上)
    内存做硬盘,开启readyboost加速,全面提升系统性能!
  • 原文地址:https://www.cnblogs.com/shadowland/p/5981602.html
Copyright © 2011-2022 走看看