b_lg_邮局(暴力dp / 预处理优化 / 四边形不等式)

为了建立邮局,应选择他们建造的位置,使每个村庄与其最近的邮局之间的距离总和最小。
你要编写一个程序,已知村庄的位置和邮局的数量,计算每个村庄和最近的邮局之间所有距离的最小可能的总和。
输出格式
第一行包含一个整数S,它是每个村庄与其最近的邮局之间的所有距离的总和。

方法一:dp

蒙的:一个邮局放在中间位置得到的距离总和最小;

  • 定义状态
    • f[i][j] 表示在前i个村庄中建j个邮局的最小距离总和
  • 思考初始化:
    • f[...][...]=+inf, f[0][0]=0
  • 思考状态转移方程
    • f[i][j]=min(f[i][j], f[k][j-1]+dist(k+1, i)),看是更优:前i个村庄中建j个邮局的最小距离 | 在前k个村庄中建j-1个以及第j个邮局在k+1到i这些村庄中建立的距离
  • 思考输出:f[V][P]

\(O(v^3 × p)\)tle之40/100...

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int V=3005, P=305, inf=0x3f3f3f3f;
int v,p,f[V][P],A[V];

int dist(int l, int r) {
    int m=l+(r-l)/2, ans=0;
    for (int i=l; i<m; i++) ans+=A[m]-A[i];
    for (int i=m+1; i<=r; i++) ans+=A[i]-A[m];
    return ans;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>v>>p;
    for (int i=1; i<=v; i++) cin>>A[i];
    memset(f, inf, sizeof f);
    f[0][0]=0;

    for (int j=1; j<=p; j++)    //邮局
    for (int i=1; i<=v; i++)    //村庄
    for (int k=0; k<i; k++) {   //少量村庄
        f[i][j]=min(f[i][j], f[k][j-1]+dist(k+1, i));
    }   
    cout << f[v][p];
    return 0;
}

预处理每个村庄中心到其它点的距离到dist[i][j]中去代替函数dist(),枯了还是40/100...

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int V=3005, P=305, inf=0x3f3f3f3f;
int v,p,f[V][P],A[V],dist[V][V];

int initdist() {
    for (int i=1; i<v; i++)
    for (int j=i+1; j<=v; j++) {
        dist[i][j]=dist[i][j-1]+A[j]-A[i+j>>1];
    }
}

int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>v>>p;
    for (int i=1; i<=v; i++) cin>>A[i];
    memset(f, inf, sizeof f); f[0][0]=0;
    initdist();

    for (int j=1; j<=p; j++)    //邮局
    for (int i=1; i<=v; i++)    //村庄
    for (int k=0; k<i; k++) {   //少量村庄
        f[i][j]=min(f[i][j], f[k][j-1]+dist[k+1][i]);
    }   
    cout << f[v][p];
    return 0;
}

复杂度分析

  • Time\(O(v^2×p)\)
  • Space\(O(vp)\)
posted @ 2020-09-15 16:32  童年の波鞋  阅读(139)  评论(0编辑  收藏  举报