【洛谷P4677】山区建小学

题目大意:给定一个长度为 N 的序列,现选出 M 个点组成一个集合,求这 N 个点到这个集合的最近距离的和是多少。

题解:
状态设计为 dp[i][j] 表示前 i 个点中选出 j 个点的最近距离和是多少,转移显然要枚举上一个选的点在哪里,即:(dp[i][j]=min(dp[k][j-1]+cost(k+1,i)))。发现在枚举进行计算时,需要提前计算一个 cost(i,j),表示 [i,j] 这段区间内的点到只有一个被选点的最近距离是多少。cost 的计算只需预处理即可,每次取区间点的中位数。总时间复杂度为(O(n^3))

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=510;

int n,m,d[maxn],f[maxn][maxn],g[maxn][maxn];

int main(){
    scanf("%d%d",&n,&m);
    d[1]=0;
    for(int i=2;i<=n;i++){
        int delta;
        scanf("%d",&delta);
        d[i]=d[i-1]+delta;
    }
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++){
            int mid=i+j>>1;
            for(int k=i;k<=j;k++){
                g[i][j]+=abs(d[mid]-d[k]);
            }
        }
    memset(f,0x3f,sizeof(f));
    f[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int k=j-1;k<i;k++){
                f[i][j]=min(f[i][j],f[k][j-1]+g[k+1][i]);
            }
        }
    }
    printf("%d
",f[n][m]);
    return 0;
}
原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10948214.html