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)\),