zoukankan      html  css  js  c++  java
  • #DP# ----- OpenJudge山区建小学

    没有记性。到DP不得不写博了,三天后又忘的干干净净。DP是啥 :-)

    一道久到不能再久的题了。

    OpenJudge  7624:山区建小学

    总时间限制: 1000ms     内存限制: 65536kB
    描述

    政府在某山区修建了一条道路,恰好穿越总共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


    因为所求为距离和最小,所以发现选择一个点a建立学校后,以a为中心向两边扩散下一个点所走的距离d=d(前一个点)+d(当前);期望重复次数越多路段d越小。然后,就有dalao证明了区间[i,j]中在中点处建学校路段和为最小(建1所学校);脑洞又开到:如果区间内点数为偶数,如何选择中点?手推数据发现其实都是一样的。在此计算的为距离和,所以实则计算的是 d总+=di*重复次数。如图:

    考虑DP:从第一个村庄开始扩展,在区间[1,i],每加入一个点i进行决策 。

    状态转移方程:f[i][j]=min(f[i][j],f[k][j-1]+w[k+1][i]); 

    f[i][j] 表示到第i个点建j所学校的最优;在区间[1.i]间枚举断点,断点前为在区间[1,k]建j-1所学校的最优,断点后为在区间[k+1,i]建1所学校的最优。

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 
     7 int n,m;
     8 int d[550][550],f[550][550],w[550][550],s[550];
     9 
    10 int pre(int a,int b){
    11     int x=0;
    12     int mid=(a+b)>>1;
    13     for(int i=a;i<=b;++i)
    14        x+=d[i][mid];
    15     return x;   
    16 }
    17 
    18 int main(){
    19     scanf("%d%d",&n,&m);
    20     for(int i=2;i<=n;++i){//s[i]---第i-1个村庄到第i个村庄间的距离 
    21         int x;
    22         scanf("%d",&x);
    23         s[i]=s[i-1]+x; 
    24     }
    25     memset(f,0x3f3f3f,sizeof(f));
    26     for(int i=1;i<=n;++i){
    27        f[i][i]=0;
    28        for(int j=1;j<=n;++j){
    29            if(i==j)d[i][j]=0;
    30            d[i][j]=d[j][i]=abs(s[i]-s[j]);//(i,j)间的距离 
    31        }
    32     }
    33     for(int i=1;i<=n;++i)//(i,j)建1所小学min 
    34        for(int j=i+1;j<=n;++j)
    35          w[i][j]=pre(i,j);  
    36     for(int i=1;i<=n;++i)f[i][1]=w[1][i];
    37     for(int i=2;i<=n;++i)// 村庄 
    38        for(int j=2;j<=min(i,m);++j)//j---学校  min(枚举的村庄数,学校数) 
    39           for(int k=j-1;k<i;++k)//min( f[i][j],建j-1所学校所达范围(1,k)+新建第j所学校范围(k+1,i)) 
    40               if(i!=j)f[i][j]=min(f[i][j],f[k][j-1]+w[k+1][i]);
    41                  
    42     printf("%d",f[n][m]);      
    43     return 0;
    44 }


     

  • 相关阅读:
    Go断后,Dart冲前,Google的野心
    gcc dynamic load library
    Go http server 高并发
    还是Go 为了伟大的未来
    windows go dll 框架
    Go cookie
    Go web ajax project
    hdoj 2844 Coins
    hdoj 1203 I NEED A OFFER!
    hdoj 2546 饭卡
  • 原文地址:https://www.cnblogs.com/wjting/p/6007347.html
Copyright © 2011-2022 走看看